XSL - 元素求和乘积

4

我有几个类似这样的物品:

<item type="goods">
    <quantity unit="pcs">172</quantity>
    <unit-price currency="PLN">420</unit-price>
    <VAT>7</VAT>
</item>

我想打印这些物品的成本总和,那么从数学上来说应该怎么做呢?
sum(quantity*unit-price)

我该如何使用xsl实现这个功能?我尝试过在for-each循环中使用变量和普通的value-of语句,但仍然得到一些奇怪的结果(由于代码质量不佳,我不会添加此代码)。


这可能会对你有所帮助:http://stackoverflow.com/questions/6181530/xslt-accumulate - Osman Alpay
@Osman Alpay:对我来说,这很复杂。无论如何,现在我能够创建每个乘法“单价*数量”值的变量。但它们没有被求和。它们在一行中打印出来。当我尝试对它们进行求和时,我会收到一个错误,提示“应返回NodeSet”... - smogg
2个回答

10

XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/root">
    <xsl:text>sum:</xsl:text>

    <xsl:call-template name="sum">
      <xsl:with-param name="nodes" select="item"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="sum">
    <xsl:param name="nodes" />
    <xsl:param name="sum" select="0" />

    <xsl:variable name="current" select="$nodes[1]" />

    <xsl:if test="$current"> 
      <xsl:call-template name="sum">
        <xsl:with-param name="nodes" select="$nodes[position() &gt; 1]" />
        <xsl:with-param name="sum" select="$sum + $current/quantity * $current/unit-price" />
      </xsl:call-template>
    </xsl:if>

    <xsl:if test="not($current)">
      <xsl:value-of select="$sum" />
    </xsl:if>

  </xsl:template>

</xsl:stylesheet>

输入XML:

<root>
  <item type="goods">
    <quantity unit="pcs">1</quantity>
    <unit-price currency="PLN">2</unit-price>
    <VAT>7</VAT>
  </item>
  <item type="goods">
    <quantity unit="pcs">10</quantity>
    <unit-price currency="PLN">20</unit-price>
    <VAT>7</VAT>
  </item>
  <item type="goods">
    <quantity unit="pcs">100</quantity>
    <unit-price currency="PLN">200</unit-price>
    <VAT>7</VAT>
  </item>
</root>

输出:

sum:20202

哇,比我想象的要复杂得多。谢谢。 - smogg
感谢您的帮助! - Amit Bhagat

3
除了Kirill的正确答案之外,还可以使用以下XPath 2.0(XSLT 2.0)解决方案:从任何支持XPath 2.0的语言中使用以下单个XPath 2.0表达式:
sum(/*/*/(quantity*unit-price))

以下是一个完整的示例,使用XSLT 2.0作为XPath 2.0的宿主:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:sequence select="sum(/*/*/(quantity*unit-price))"/>
 </xsl:template>
</xsl:stylesheet>

当应用于以下 XML 文档时:
<items>
    <item type="goods">
        <quantity unit="pcs">1</quantity>
        <unit-price currency="PLN">2</unit-price>
        <VAT>7</VAT>
    </item>
    <item type="goods">
        <quantity unit="pcs">10</quantity>
        <unit-price currency="PLN">20</unit-price>
        <VAT>7</VAT>
    </item>
    <item type="goods">
        <quantity unit="pcs">100</quantity>
        <unit-price currency="PLN">200</unit-price>
        <VAT>7</VAT>
    </item>
</items>

所需的正确结果已生成

20202

II. 使用 FXSL 1.x 的 transform-and-sum 模板/函数的 XSLT 1.0 解决方案

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/"
xmlns:func-transform="f f:func-transform"
exclude-result-prefixes="xsl func-transform"
>
   <xsl:import href="transform-and-sum.xsl"/>

   <!-- to be applied on testTransform-and-sum5.xml -->

   <xsl:output method="text"/>

   <func-transform:func-transform/>

    <xsl:template match="/">
      <xsl:call-template name="transform-and-sum">
        <xsl:with-param name="pFuncTransform" 
                        select="document('')/*/func-transform:*[1]"/>
        <xsl:with-param name="pList" select="/*/*"/>
      </xsl:call-template>
    </xsl:template>

    <xsl:template match="func-transform:*" mode="f:FXSL">
      <xsl:param name="arg1" select="0"/>
      <xsl:value-of select="$arg1/quantity * $arg1/unit-price "/>
    </xsl:template>
</xsl:stylesheet>

当在同一XML文档(上述)上应用此转换时,将产生相同的正确结果:
20202

请注意:使用FXSL,您无需实现“第N次”明确递归,解决方案紧凑,完全消除了编写递归时潜在的错误。
总体而言,总开发时间、可读性和灵活性都得到了显著改善。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接