« Concurrent calls to the same session object not allowed | Main | Happy Halloween »

XSLT: Sum of products from multiple nodes

October 31, 2003
Keywords:

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>



Trackback Pings

TrackBack URL for this entry:
http://blog.davidkaspar.com/cgi-bin/f39fmcnswgv.cgi/72

Comments

  1. rohit mathur Says:

    no gravatar

    thanx

    this came in really handy

    will definitely use it...

  2. thank you Says:

    no gravatar

    very accurate and helpful

  3. Bruno Says:

    no gravatar

    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"

  4. goku Says:

    no gravatar

    it was very useful.
    Thank you very much.

  5. VQ Says:

    no gravatar

    Awesome solution!! This problem had been racking my brain for days until I stumbled across this solution...

Post a Comment

 *

 *

 

 
Remember Me?

* (you may use HTML tags for style)