尽管XSLT变量是不可变的,但尝试增加变量

时间:2016-10-18 07:37:54

标签: xml xslt

我正在尝试使用XSLT将1个XML文件转换为另一个XML文件,其中生成的XML文件是执行查询的结果。不幸的是,根据我的理解,XSLT中的变量是不可变的,无法更改。我想知道是否有任何其他方法可以添加值,以便我可以获得为相关部分返回的任何查询的总值。

正如您在原始XML文件中看到的那样,总数会计算每个条目中所有年龄组编号的总值。我使用XSLT查询根据查询的年龄范围$ AGE_GROUP1和$ AGE_GROUP2提取出不同的年龄组,但由于任何声明的变量都是不可变的,我想不出一种方法来添加年龄组的查询值

以下是源XML文件:

<?xml version="1.0" encoding="UTF-8"?>
<Replacements>
   <Entry>
      <Year>2005</Year>
      <Month>DEC</Month>
      <Reason>Blemish on Card</Reason>
      <Age>
         <Group>
            <Range>Total</Range>
            <value>16</value>
         </Group>
         <Group>
            <Range>16-17</Range>
            <value>3</value>
         </Group>
         <Group>
            <Range>18-25</Range>
            <value>12</value>
         </Group>
         <Group>
            <Range>26-29</Range>
            <value>1</value>
         </Group>
      </Age>
   </Entry>
   <Entry>
      <Year>2005</Year>
      <Month>DEC</Month>
      <Reason>Damaged</Reason>
      <Age>
         <Group>
            <Range>Total</Range>
            <value>7</value>
         </Group>
         <Group>
            <Range>16-17</Range>
            <value>6</value>
         </Group>
         <Group>
            <Range>18-25</Range>
            <value>0</value>
         </Group>
         <Group>
            <Range>26-29</Range>
            <value>1</value>
         </Group>
      </Age>
   </Entry>
</Replacements>

以下XSLT仅提取3个年龄组中的相关2个(仅提取14至24岁的年龄组),因此原始数据集中每个条目的1个年龄组不会输出到生成的XML文件:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0">

    <xsl:variable name = "QUERY_YEAR1" select = "2005" />
    <xsl:variable name = "QUERY_YEAR2" select = "2007" />
    <xsl:variable name = "AGE_GROUP1" select = "14" />
    <xsl:variable name = "AGE_GROUP2" select = "24" />
    <xsl:variable name = "TOTAL" select = "0" />

    <xsl:output method="xml" indent="yes" />
    <xsl:strip-space elements="*" />

    <xsl:template match="/">

        <xsl:for-each select="Replacements/Entry">
            <xsl:if test="$QUERY_YEAR1 &lt;= Year/text() and $QUERY_YEAR2 &gt;= Year/text()">
                <Entry>
                    <Year>
                        <xsl:value-of select="Year/text()" />
                    </Year>
                    <Month>
                        <xsl:value-of select="Month/text()" />
                    </Month>
                    <Reason>
                        <xsl:value-of select="Reason/text()" />
                    </Reason>
                    <xsl:for-each select="Age/Group">

                        <!-- $AGE_GROUP1 < 16 & 17, $AGE_GROUP2 > 16 & 17 for age group 16-17 (e.g. $AGE_GROUP1 = 14 & $AGE_GROUP2 = 30 -->
                        <xsl:if test="$AGE_GROUP1 &lt;= number(substring(Range/text(), 1, 2)) and $AGE_GROUP1 &lt;= number(substring(Range/text(), 4, 2)) and $AGE_GROUP2 &gt;= number(substring(Range/text(), 1, 2)) and $AGE_GROUP2 &gt;= number(substring(Range/text(), 4, 2)) and not(Range/text() = 'Total') and not(Range/text() = '80+')">

                            <!-- Add to $TOTAL value -->
                            <xsl:variable name = "TOTAL" select = "number($TOTAL) + number(value/text())" />

                            <AgeGroup>
                                <Range>
                                    <xsl:value-of select="Range/text()" />
                                </Range>
                                <value>
                                    <xsl:value-of select="value/text()" />
                                </value>
                            </AgeGroup>
                        </xsl:if>

                        <!-- $AGE_GROUP1 < 30 & 39, $AGE_GROUP2 = 30 & < 39 for age group 30-39 (e.g. $AGE_GROUP1 = 14 & $AGE_GROUP2 = 30 -->
                        <!-- $AGE_GROUP1 < 26 & 29, $AGE_GROUP2 > 26 & < 29 for age group 26-29 (e.g. $AGE_GROUP1 = 19 & $AGE_GROUP2 = 27 -->
                        <xsl:if test="$AGE_GROUP1 &lt;= number(substring(Range/text(), 1, 2)) and $AGE_GROUP1 &lt;= number(substring(Range/text(), 4, 2)) and $AGE_GROUP2 &gt;= number(substring(Range/text(), 1, 2)) and $AGE_GROUP2 &lt;= number(substring(Range/text(), 4, 2)) and not(Range/text() = 'Total') and not(Range/text() = '80+')">

                            <!-- Add to $TOTAL value -->
                            <xsl:variable name = "TOTAL" select = "number($TOTAL) + number(value/text())" />

                            <AgeGroup>
                                <Range>
                                    <xsl:value-of select="Range/text()" />
                                </Range>
                                <value>
                                    <xsl:value-of select="value/text()" />
                                </value>
                            </AgeGroup>
                        </xsl:if>

                        <!-- $AGE_GROUP1 > 18 & < 25, $AGE_GROUP2 > 18 & 25 for age group 18-25 (e.g. $AGE_GROUP1 = 19 & $AGE_GROUP2 = 27 -->
                        <xsl:if test="$AGE_GROUP1 &gt;= number(substring(Range/text(), 1, 2)) and $AGE_GROUP1 &lt;= number(substring(Range/text(), 4, 2)) and $AGE_GROUP2 &gt;= number(substring(Range/text(), 1, 2)) and $AGE_GROUP2 &gt;= number(substring(Range/text(), 4, 2)) and not(Range/text() = 'Total') and not(Range/text() = '80+')">

                            <!-- Add to $TOTAL value -->
                            <xsl:variable name = "TOTAL" select = "number($TOTAL) + number(value/text())" />

                            <AgeGroup>
                                <Range>
                                    <xsl:value-of select="Range/text()" />
                                </Range>
                                <value>
                                    <xsl:value-of select="value/text()" />
                                </value>
                            </AgeGroup>
                        </xsl:if>

                    </xsl:for-each>

                    <!-- Total calculation for all values within returned age groups -->
                    <AgeGroup>
                        <Range>
                            <xsl:value-of select="'Total'" />
                        </Range>
                        <value>
                            <xsl:value-of select="$TOTAL" />
                        </value>
                    </AgeGroup>

                </Entry>
            </xsl:if>
        </xsl:for-each>

    </xsl:template>

</xsl:stylesheet>

我现在得到的是以下内容,它没有提取的年龄组值的总值,因为我无法在每个时刻分配变量$ TOTAL:

<?xml version="1.0" encoding="UTF-8"?>
<Entry>
   <Year>2005</Year>
   <Month>DEC</Month>
   <Reason>Blemish on Card</Reason>
   <AgeGroup>
      <Range>16-17</Range>
      <value>3</value>
   </AgeGroup>
   <AgeGroup>
      <Range>18-25</Range>
      <value>12</value>
   </AgeGroup>
   <AgeGroup>
      <Range>Total</Range>
      <value>0</value>
   </AgeGroup>
</Entry>
<Entry>
   <Year>2005</Year>
   <Month>DEC</Month>
   <Reason>Damaged</Reason>
   <AgeGroup>
      <Range>16-17</Range>
      <value>6</value>
   </AgeGroup>
   <AgeGroup>
      <Range>18-25</Range>
      <value>0</value>
   </AgeGroup>
   <AgeGroup>
      <Range>Total</Range>
      <value>0</value>
   </AgeGroup>
</Entry>

我需要的是:

<?xml version="1.0" encoding="UTF-8"?>
<Entry>
   <Year>2005</Year>
   <Month>DEC</Month>
   <Reason>Blemish on Card</Reason>
   <AgeGroup>
      <Range>16-17</Range>
      <value>3</value>
   </AgeGroup>
   <AgeGroup>
      <Range>18-25</Range>
      <value>12</value>
   </AgeGroup>
   <AgeGroup>
      <Range>Total</Range>
      <value>15</value>
   </AgeGroup>
</Entry>
<Entry>
   <Year>2005</Year>
   <Month>DEC</Month>
   <Reason>Damaged</Reason>
   <AgeGroup>
      <Range>16-17</Range>
      <value>6</value>
   </AgeGroup>
   <AgeGroup>
      <Range>18-25</Range>
      <value>0</value>
   </AgeGroup>
   <AgeGroup>
      <Range>Total</Range>
      <value>6</value>
   </AgeGroup>
</Entry>

我用来执行XSLT的命令是:java -jar saxon9he.jar sample1.xml sample1.xslt > out.xml

我只是想知道是否有人知道如何添加值,就像输入if条件时在XSLT中看到的那样,以便将该年龄组的值添加到总数中,并且总计可以在输出XML文件中返回吗?

1 个答案:

答案 0 :(得分:1)

我认为,不是有三个单独的表达式来测试重叠范围,你可以将它减少到只有一个条件....

 <xsl:for-each select="Age/Group
                       [$AGE_GROUP1 &lt;= number(substring(Range/text(), 4, 2))]
                       [$AGE_GROUP2 &gt;= number(substring(Range/text(), 1, 2))]">

但是就获得总数而言,您只需使用sum函数来总结所有value元素。您可以将上面的表达式放在变量...

<xsl:variable name="groups" select="Age/Group[$AGE_GROUP1 &lt;= number(substring(Range/text(), 4, 2))][$AGE_GROUP2 &gt;= number(substring(Range/text(), 1, 2))]" />

然后你得到总数如下:

<xsl:value-of select="sum($groups/value)" />

试试这个XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0">

    <xsl:variable name = "QUERY_YEAR1" select = "2005" />
    <xsl:variable name = "QUERY_YEAR2" select = "2007" />
    <xsl:variable name = "AGE_GROUP1" select = "14" />
    <xsl:variable name = "AGE_GROUP2" select = "24" />
    <xsl:variable name = "TOTAL" select = "0" />

    <xsl:output method="xml" indent="yes" />
    <xsl:strip-space elements="*" />

    <xsl:template match="/">

        <xsl:for-each select="Replacements/Entry">
            <xsl:if test="$QUERY_YEAR1 &lt;= Year/text() and $QUERY_YEAR2 &gt;= Year/text()">
                <Entry>
                    <Year>
                        <xsl:value-of select="Year/text()" />
                    </Year>
                    <Month>
                        <xsl:value-of select="Month/text()" />
                    </Month>
                    <Reason>
                        <xsl:value-of select="Reason/text()" />
                    </Reason>
                    <xsl:variable name="groups" select="Age/Group[$AGE_GROUP1 &lt;= number(substring(Range/text(), 4, 2))][$AGE_GROUP2 &gt;= number(substring(Range/text(), 1, 2))]" />
                    <xsl:for-each select="$groups">
                            <AgeGroup>
                                <Range>
                                    <xsl:value-of select="Range/text()" />
                                </Range>
                                <value>
                                    <xsl:value-of select="value/text()" />
                                </value>
                            </AgeGroup>
                    </xsl:for-each>
                    <!-- Total calculation for all values within returned age groups -->
                    <AgeGroup>
                        <Range>
                            <xsl:value-of select="'Total'" />
                        </Range>
                        <value>
                            <xsl:value-of select="sum($groups/value)" />
                        </value>
                    </AgeGroup>
                </Entry>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

编辑:在回答您的评论时,如果您的年龄范围为&#34; 80 +&#34;我想你可以像这样调整groups变量:

<xsl:variable name="groups" select="Age/Group
                    [substring(Range/text(), 3, 1) = '+' or $AGE_GROUP1 &lt;= number(substring(Range/text(), 4, 2))]
                    [$AGE_GROUP2 &gt;= number(substring(Range/text(), 1, 2))]" />