The XSL method sum(/foo)
sums the value of all foo nodes in current context. If you, however, want to sum the product between two or more nodes the sum(/foo * /bar)
is not sufficient as the product does not return a nodeset and thus sum() fails.
I found one way to sum products of multiple nodes and is to construct a temporary variable with the products, convert that variable to a nodeset and the sum all nodes in that temporary node set.
The function that converts a variable to a nodeset seems to be XSLT specific and the solution below is for Xalan since we are using it in our app. If you are using MSXML you will have to change the namespace but the name of the function is the same.
XML:
<Order>
<OrderLine>
<Quantity>
<Amount>2</Amount>
</Quantity>
<Price>
<UnitPrice>25</UnitPrice>
</Price>
</OrderLine>
<OrderLine>
<Quantity>
<Amount>10</Amount>
</Quantity>
<Price>
<UnitPrice>2</UnitPrice>
</Price>
</OrderLine>
<OrderLine>
<Quantity>
<Amount>23</Amount>
</Quantity>
<Price>
<UnitPrice>6</UnitPrice>
</Price>
</OrderLine>
</Order>
XSL:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xalan="http://xml.apache.org/xalan">
<xsl:template match="/Order">
<root>
<xsl:variable name="tmpTotal">
<total_amount>
<xsl:for-each select="OrderLine">
<item>
<xsl:value-of select="Quantity/Amount * Price/UnitPrice"/>
</item>
</xsl:for-each>
</total_amount>
</xsl:variable>
<total>
<xsl:variable name="myTotal" select="xalan:nodeset($tmpTotal)"/>
<xsl:value-of select="sum($myTotal/total_amount/item)" />
</total>
</root>
</xsl:template>
</xsl:stylesheet>
thanx
this came in really handy
will definitely use it…
very accurate and helpful
Note to make it work with .NET XslTransform. You have to use the msxsl:node-set() function:
<xsl:value-of select=”sum( msxsl:node-set($myTotal)/total_amount/item )” />
Oh, and to have access to that function, add this namespace to your XSLT tag:
xmlns:msxsl=”urn:schemas-microsoft-com:xslt”
it was very useful.
Thank you very much.
Awesome solution!! This problem had been racking my brain for days until I stumbled across this solution…