在XSLT中求和计算值

时间:2014-02-16 07:52:22

标签: xml xslt

我试图将所有商品价格的总和乘以他们购买的数量,例如(给定以下内容)......

<item>
   <itemPrice>10</itemPrice>
   <itemQty>5</itemQty> 
</item>
<item>
   <itemPrice>5</itemPrice>
   <itemQty>7</itemQty> 
</item>

我希望总价值85美元。我尝试了以下内容,但不是将每个计算项目购买添加到总变量,而是将所有值连接成一个字符串...

<xsl:template name="itemsTotal">
    <xsl:variable name="total" select="0" />

    <xsl:for-each select="item">
        <xsl:value-of select="$total + (./itemQty * ./itemPrice)" />
    </xsl:for-each>
</xsl:template>

获得我想要的东西的最佳途径是什么?我可以对我的模板进行修改吗?

2 个答案:

答案 0 :(得分:1)

假设您正在使用XSLT 1.0并假设您的处理器支持EXSLT node-set()函数(几乎可以肯定),并假设我们在您的XML输入示例中添加了一个根元素,并假设您确实希望结果为是10 * 5 + 5 * 7 85 ,而不是 80 ,请尝试以下样式表:

<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:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

<xsl:template match="/">
<!-- ... -->
<xsl:variable name="extPrices">
    <xsl:for-each select="items/item">
        <extPrice>
            <xsl:value-of select="itemPrice*itemQty" />
        </extPrice>
    </xsl:for-each>
</xsl:variable>
<xsl:variable name="subTotal" select="sum(exsl:node-set($extPrices)/extPrice)" />

<subTotal><xsl:value-of select="$subTotal" /></subTotal>
<!-- ... -->    
</xsl:template>
</xsl:stylesheet>

应用于更正的输入:

<items>
    <item>
       <itemPrice>10</itemPrice>
       <itemQty>5</itemQty> 
    </item>
    <item>
       <itemPrice>5</itemPrice>
       <itemQty>7</itemQty> 
    </item>
</items>

结果是:

<?xml version="1.0" encoding="utf-8"?>
<subTotal>85</subTotal>

答案 1 :(得分:1)

迭代通过XSLT 1.0中的递归来解决。

<xsl:template name="itemTotal">
  <xsl:param name="item" select="." />
  <xsl:param name="carryOver" select="0" />

  <xsl:variable name="runningTotal" select="
    $carryOver + $item/itemPrice * $item/itemQty
  " />
  <xsl:variable name="nextItem" select="$item/following-sibling::item[1]" />

  <xsl:choose>
    <xsl:when test="not($nextItem)">
      <xsl:value-of select="$runningTotal" />
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="itemTotal">
        <xsl:with-param name="item" select="$nextItem" />
        <xsl:with-param name="carryOver" select="$runningTotal" />
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

可以像这样调用

<xsl:call-template name="itemTotal">
  <xsl:with-param name="item" select="root/item[1]" />
</xsl:call-template>

和输出

85

注释

  • 这是XSLT 1.0。如果您的XSLT处理器支持XSLT 2.0和XQuery,那么您可以使用XQuery FLWOR表达式更优雅地解决这个问题。
  • itemTotal模板是尾递归的,因此可能会被XSLT处理器优化为循环。在这种情况下,即使对于高<item>计数,也不会发生堆栈溢出。
  • 模板目前取决于兄弟姐妹的项目(因此使用following-sibling)。这适用于您的示例,但可能必须适应其他输入。
  • 无需扩展功能,但如果您的XSLT处理器支持它们,您可能最好使用基于node-set()的解决方案,例如michael's answer节目。