2013-05-02 88 views
1

如何使用XSLT 1.0,如何總結給定節點下的子節點,同時用另一組節點中的數據以優雅的方式修改內容?假設我有這個xml:如何使用來自其他節點的計算數據來彙總節點

<Root> 
    <ExchangeRates> 
     <ExchangeRate> 
      <CurrencyCode>USD</CurrencyCode> 
      <Rate>6.4</Rate> 
     </ExchangeRate> 
     <ExchangeRate> 
      <CurrencyCode>EUR</CurrencyCode> 
      <Rate>8.44</Rate> 
     </ExchangeRate> 
     <ExchangeRate> 
      <CurrencyCode>SEK</CurrencyCode> 
      <Rate>1</Rate> 
     </ExchangeRate> 
    </ExchangeRates> 
    <Prices> 
     <Price> 
      <Currency>SEK</Currency> 
      <Amount>10000</Amount> 
     </Price> 
     <Price> 
      <Currency>EUR</Currency> 
      <Amount>1000</Amount> 
     </Price> 
     <Price> 
      <Currency>USD</Currency> 
      <Amount>1000</Amount> 
     </Price> 
    </Prices> 
</Root> 

我想要在ExchangeRates的幫助下轉換成SEK的所有金額的總和。結果應該是:

<SumInSEK>24840</SumInSEK> 

如果我不需要轉換金額,我只需使用xpath sum()函數。在這種情況下可以使用該功能嗎?

回答

3

另一種可能的解決方案,無需遞歸調用但帶有exsl擴展名。 這使用@softwarebear的密鑰定義形式。

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
     xmlns:exsl="http://exslt.org/common" 
     extension-element-prefixes="exsl"> 

    <xsl:key name="rates" match="//ExchangeRate/Rate" use="parent::*/child::CurrencyCode/text()"/> 

    <xsl:template match="/" > 
     <xsl:apply-templates select="//Prices"/> 
    </xsl:template> 

    <xsl:template match="Prices"> 
     <SUmInSEK> 
      <xsl:variable name="price_SEK"> 
       <xsl:apply-templates mode="SEK" /> 
      </xsl:variable> 
      <xsl:value-of select="sum(exsl:node-set($price_SEK)//price_SEK)"/> 
     </SUmInSEK> 
    </xsl:template> 

    <xsl:template match="Price" mode="SEK"> 
     <price_SEK> 
      <xsl:value-of 
      select="number(Amount) * number(key('rates', Currency))" /> 
     </price_SEK> 
    </xsl:template> 
</xsl:stylesheet> 

在室內用輸出

<SUmInSEK>24840</SUmInSEK> 
+0

不錯,我選擇使用這個解決方案。從中學到了一點。我很好奇的兩件事:爲什麼在價格模板中使用mode屬性而不是匹配模式?爲什麼在price_SEK節點名稱之前有兩個斜線? – Ogawa 2013-05-03 10:33:22

+0

這個小例子也可以在沒有模式的情況下工作。但是,如果您必須使用「價格」標籤執行其他操作,則仍然可以添加其他價格模板(不含模式)。你是正確的一個斜線會做。 (似乎我是一個粗心大意的人) – 2013-05-03 11:59:20

2

我認爲這可能很簡單......但我不認爲你可以在這個場合使用sum()...我能做的最好的是遞歸模板。

?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" 
> 
    <xsl:key name="rates" match="//ExchangeRate/Rate" use="parent::*/child::CurrencyCode/text()"/> 

    <xsl:template match="//Prices"> 
    <SUmInSEK> 
     <xsl:call-template name="sum"/> 
    </SUmInSEK> 
    </xsl:template> 

    <xsl:template name="sum"> 
    <xsl:param name="iterator" select="1"/> 
    <xsl:param name="total" select="0"/> 
    <xsl:variable name="price" select="child::Price[$iterator]"/> 
    <xsl:variable name="current"> 
     <xsl:value-of select="number($price/child::Amount) * number(key('rates', $price/child::Currency))"/> 
    </xsl:variable> 
    <xsl:variable name="newtotal"> 
     <xsl:value-of select="$total + $current"/> 
    </xsl:variable> 
    <xsl:choose> 
     <xsl:when test="$price/following-sibling::Price"> 
     <xsl:call-template name="sum"> 
      <xsl:with-param name="iterator" select="$iterator+1"/> 
      <xsl:with-param name="total" select="$newtotal"/> 
     </xsl:call-template> 
     </xsl:when> 
     <xsl:otherwise> 
     <xsl:value-of select="$total + $current"/> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 

    <xsl:template match="* | /"> 
    <xsl:apply-templates /> 
    </xsl:template> 

    <xsl:template match="text() | @*"> 
    </xsl:template> 

    <xsl:template match="processing-instruction() | comment()" /> 

</xsl:stylesheet> 
+0

比我的遞歸嘗試更好。 +1購買爲什麼使用迭代器和Price節點作爲參數? – 2013-05-02 17:08:09

+0

只是我工作的第一個解決方案,我猜我可以沿價格節點的方式工作,作爲當前的環境,而不是......哦,只是讀你的答案......我不知道我們可以做到這一點8- ) – softwarebear 2013-05-03 06:43:09

相關問題