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 的帮助下将所有金额转换为瑞典克朗的总和。结果应该是:

<SumInSEK>24840</SumInSEK>

如果我不必转换金额,我只需使用 xpath sum() 函数。在这种情况下可以使用该功能吗?

4

2 回答 2

4

另一种没有递归调用但具有 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>
于 2013-05-02T17:04:08.893 回答
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>
于 2013-05-02T15:19:16.557 回答