XSLT: Sum of products from multiple nodes

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>

5 thoughts on “XSLT: Sum of products from multiple nodes”

  1. 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”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.