相乘2个数然后求和

我有一个困难的时候,试图做一些似乎应该很容易做的事情。 我基本上想要在一个节点中乘以2个数字,然后将所有节点的总数相加。 这是我试过的XSLT代码。

<xsl:value-of select="sum(Parts/Part/Quantity * Parts/Part/Rate)"/> 

此代码导致一个错误,指出“函数和的参数1不能转换为节点集”。

有没有人有什么错误的想法,或者我怎么能够完成我想要做的事情?

这里有三种可能的解决scheme

解决scheme1 ​​XSLT2:

 <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:sequence select="sum(/*/*/(rate * quantity))"/> </xsl:template> </xsl:stylesheet> 

将此转换应用于以下XML文档时

 <parts> <part> <rate>0.37</rate> <quantity>10</quantity> </part> <part> <rate>0.03</rate> <quantity>10</quantity> </part> </parts> 

想要的结果是

4

XSLT 2.0解决scheme使用的事实是,在XPath 2.0中允许最后一个“/”运算符的正确参数可以是expression式或通常是函数。 这个expression式/函数应用于目前为止select的每个节点作为上下文节点,并且每个函数应用程序产生一个结果。

Solution2 XSLT 1.0:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template match="/"> <xsl:call-template name="sumProducts"> <xsl:with-param name="pList" select="*/*"/> </xsl:call-template> </xsl:template> <xsl:template name="sumProducts"> <xsl:param name="pList"/> <xsl:param name="pAccum" select="0"/> <xsl:choose> <xsl:when test="$pList"> <xsl:variable name="vHead" select="$pList[1]"/> <xsl:call-template name="sumProducts"> <xsl:with-param name="pList" select="$pList[position() > 1]"/> <xsl:with-param name="pAccum" select="$pAccum + $vHead/rate * $vHead/quantity"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$pAccum"/> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet> 

当应用于上述XML文档时,会产生正确的结果

4

这是一个典型的XSLT 1.0recursion解决scheme请注意sumProducts模板是如何recursion调用自身的 ,直到处理了传入参数$pList的整个input列表。

Solution3 FXSL(XSLT 1.0):

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="http://exslt.org/common" xmlns:test-map-product="test-map-product" exclude-result-prefixes="xsl ext test-map-product" > <xsl:import href="sum.xsl"/> <xsl:import href="map.xsl"/> <xsl:import href="product.xsl"/> <!-- This transformation is to be applied on: salesMap.xml It contains the code of the "sum of products" from the article "The Functional Programming Language XSLT" --> <test-map-product:test-map-product/> <xsl:output method="text"/> <xsl:template match="/"> <!-- Get: map product /sales/sale --> <xsl:variable name="vSalesTotals"> <xsl:variable name="vTestMap" select="document('')/*/test-map-product:*[1]"/> <xsl:call-template name="map"> <xsl:with-param name="pFun" select="$vTestMap"/> <xsl:with-param name="pList1" select="/sales/sale"/> </xsl:call-template> </xsl:variable> <!-- Get sum map product /sales/sale --> <xsl:call-template name="sum"> <xsl:with-param name="pList" select="ext:node-set($vSalesTotals)/*"/> </xsl:call-template> </xsl:template> <xsl:template name="makeproduct" match="*[namespace-uri() = 'test-map-product']"> <xsl:param name="arg1"/> <xsl:call-template name="product"> <xsl:with-param name="pList" select="$arg1/*"/> </xsl:call-template> </xsl:template> </xsl:stylesheet> 

将此转换应用于以下XML文档时

 <sales> <sale> <price>3.5</price> <quantity>2</quantity> <Discount>0.75</Discount> <Discount>0.80</Discount> <Discount>0.90</Discount> </sale> <sale> <price>3.5</price> <quantity>2</quantity> <Discount>0.75</Discount> <Discount>0.80</Discount> <Discount>0.90</Discount> </sale> </sales> 

产生正确的结果

7.5600000000000005

在每个sale的最后一种情况下,我们计算pricequantity和所有可用(可变数量) discount

FXSL 是高阶函数的纯XSLT实现。 在这个例子中,使用高阶函数f:map()来映射每个sale元素的子元素列表上的函数f:product() 。 然后将结果相加以产生最终结果。

Dimitre的所有解决scheme都能正常工作,他说得对,您不需要使用扩展function,但是有时它使生活更轻松。 这不是太有害,尤其是当您使用跨多个XSLT处理器支持的exslt扩展。 此外,您得到序列错误的原因可能是因为您使用的是XSLT 1处理器。

如果您想坚持使用您select的解决scheme,则需要使用Saxon或其他支持XSLT 2的XSLT处理器。

否则,下面是在XSLT 1中使用它的一种替代方法。这在大多数XSLT处理器中都能正常工作,并且某些人可能比recursion版本更容易理解。 就个人而言,我更喜欢recursion版本(Dimitre的第三个build议),因为它更便于携带。

 <xsl:stylesheet version="1.0" xmlns:ex="http://exslt.org/common" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text"/> <xsl:template name="GetProducts"> <xsl:param name="left"/> <xsl:param name="right"/> <xsl:for-each select="$left/text()"> <product> <xsl:value-of select="number(.) * number($right[position()])"/> </product> </xsl:for-each> </xsl:template> <xsl:template match="/"> <xsl:variable name="products"> <xsl:call-template name="GetProducts"> <xsl:with-param name="left" select="Parts/Part/Rate"/> <xsl:with-param name="right" select="Parts/Part/Quantity"/> </xsl:call-template> </xsl:variable> <xsl:value-of select="sum(ex:node-set($products)/product)"/> </xsl:template> </xsl:stylesheet>