# RE: XSL problem using sum() function

 Subject: RE: XSL problem using sum() function From: "Michael Kay" Date: Thu, 18 Nov 2004 18:12:01 -0000
(Dave P: could we have this in the FAQ please?)

The general problem of summing over a computed value has three noteworthy
solutions. Let's use f(\$x) for the function that computes the number you
want to total, given a node \$x (the canonical example is summing price times
quantity, where f() is \$x/@price * \$x/@qty), and let's use \$seq for the
sequence of nodes that you want to sum over. That is, you want to apply f()
to each node in \$seq and return the sum of the results.

(a) In XPath 2.0

sum(for \$i in \$seq return f(\$i))

In fact, in the Oct 2004 draft it's even simpler, but this won't be
available until Saxon 8.2:

sum(\$seq/f(.))

Concrete examples:

sum(//item/(@price * @qty))

sum(//item/number(translate(., '\$', '')))

(b) In XSLT 1.0 with xx:node-set() extension

Create a result-tree-fragment containing the computed numeric values as
values of element or attribute nodes; use xx:node-set() to convert this RTF
to a node-set, and then use sum() over the nodes.  For example:

<xsl:variable name="temp">
<xsl:for-each select="\$seq">
<item value="{f(.)}"/>
</xsl:for-each>
</xsl:variable>

or more concretly,

<xsl:variable name="temp">
<xsl:for-each select="//item">
<item value="{@price * @qty}"/>
</xsl:for-each>
</xsl:variable>

<xsl:value-of select="sum(xx:node-set(\$temp)/item/@value)"/>

(c) In pure XSLT 1.0

Recurse over the input sequence using a recursive named template:

<xsl:template name="total">
<xsl:param name="seq"/>
<xsl:param name="total-so-far" select="0"/>
<xsl:choose>
<xsl:when test="\$seq">
<xsl:call-template name="total">
<xsl:with-param name="seq"
select="\$seq[position()!=1]"/>
<xsl:with-param name="total-so-far"
select="\$total-so-far + f(\$seq[1])"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="\$total-so-far"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

Michael Kay
http://www.saxonica.com/

> -----Original Message-----
> From: Christopher Hansen [mailto:chansen1@xxxxxxxxx]
> Sent: 18 November 2004 17:29
> To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> Subject:  XSL problem using sum() function
>
> Im trying to get the sum of all salaries for company:BG (see XML
> below).  Im using translate to remove the '\$' and ',' from the dollar
> amounts and then, trying to sum them up.  But i get the error that it
> cannot convert String to NodeList.  I've tried some other workarounds
> but i just cant seem to get it.   Any ideas?
> Thanks
> Chris
>
>
> The XSL:
>
> <?xml version="1.0"?>
> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
> version="1.0">
>
>         <xsl:output method="html"/>
>
>         <xsl:variable name="workssection"
> select="document('works.xml')" />
>         <xsl:variable name="empsection"
> select="document('employees.xml')" />
>
>         <xsl:template match="/">
>         <xsl:for-each select="\$workssection//works-for/" >
>           <xsl:if test ="company-name = 'BG'" >
>             <xsl:variable name="trans"
> select="translate(salary,'\$,','')" />
>             <p><xsl:value-of select="sum(\$trans)" /></p>
>           </xsl:if>
>         </xsl:for-each>
>
>         </xsl:template>
> </xsl:stylesheet>
>
>
>
> A portion of the XML file:
> <works>
>       <works-for>
>             <emp-name>John Doe</emp-name>
>             <company-name>BG</company-name>
>             <company-city>Ames</company-city>
>             <salary>\$70,000</salary>
>       </works-for>
>
>       <works-for>
>             <emp-name>Margaret Thatcher</emp-name>
>             <company-name>BG</company-name>
>             <company-city>London</company-city>
>             <salary>\$7,000,000</salary>
>       </works-for>
>       ....

### PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!