2016-10-18 63 views
0

我試圖使用XSLT將1個XML文件轉換爲另一個,其中生成的XML文件是執行查詢的結果。不幸的是,據我所知,XSLT中的變量是不可變的,不能改變。我想知道是否有其他方法可以將這些值相加,這樣我就可以得到相關部分返回的任何查詢的總值。雖然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僅提取有關2 3個年齡組(只提取年齡組從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

我想,而不是有三個獨立的表達式來測試重疊的範圍,可以減少它只是一個條件....

<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> 

編輯:在回答你的評論,如果你的年齡範圍爲「80+」,我認爲你可以調整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))]" /> 
+0

謝謝!那是我需要的。如果我得到了原始XML文件中的另一個年齡組, 80+ ,我該怎麼辦? – iteong

+0

我已經對答案進行了編輯,希望能夠展示如何調整表達式以應對此問題。 –

+0

完美!它很棒!愛堆棧溢出= D – iteong