【问题标题】:Summing calculated values in XSLT在 XSLT 中对计算值求和
【发布时间】:2014-02-16 07:52:22
【问题描述】:

我试图将所有商品价格的总和乘以它们的购买数量,例如(鉴于以下情况)...

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

获得所需内容的最佳方式是什么?我可以对我的模板进行修改吗?

【问题讨论】:

    标签: xml xslt


    【解决方案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 处理器优化为一个循环。在这种情况下,即使&lt;item&gt; 计数很高,也不会发生堆栈溢出。
    • 模板当前依赖于兄弟项目(因此使用following-sibling)。这适用于您的示例,但可能需要适应其他输入。
    • 无需扩展功能,但如果您的 XSLT 处理器支持它们,您最好使用基于 node-set() 的解决方案,如 michael's answer 所示。

    【讨论】:

      【解决方案2】:

      假设您正在使用 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>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-22
        • 1970-01-01
        • 2011-02-15
        • 2021-10-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多