Re: [xsl] sum function

Subject: Re: [xsl] sum function
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Fri, 16 Nov 2001 15:32:12 +0000
Hi Jan,

> How do I use the sum function on xml such as:
>
> <Amount>12,345.12</Amount>
> <Amount>132,345.12</Amount>
> <Amount>2,345.12</Amount>
>
> If I use Total Price = <xsl:value-of select="sum(//Amount)"/> I get the
> result NaN. However, if the data does not contain ',' the sum works
> correctly.

This is because XPath can't convert '2,345.12' to a number (due to the
comma, as you found). The best solution is to change your XML source
document so that it doesn't contain commas in numeric values. This is
the best solution because (a) it makes your XSLT simple (you can use
sum()) and (b) according to XML Schema and therefore the rest of the
XML world, the text representation of numbers doesn't contain commas;
removing them will mean that you can use XML Schema or other languages
that use the XML Schema data types with your XML as well.

If you can't do that, then you need a recursive template that will
enable you to do the conversion of the string value of the Amount
elements to the numbers that you want them to be. The conversion is
really simple - get rid of the commas with the translate() function.
With $amount being an Amount element:

  translate($amount, ',', '')

You could use one of Dimitre's generic templates, or the following
(tail-)recursive template, which works through the Amount elements one
by one, keeping track of the subtotal as it goes, and finally returns
the total when it runs out of Amount elements:

<xsl:template name="sumAmounts">
  <xsl:param name="amounts" select="Amount" />
  <xsl:param name="subtotal" select="0" />
  <xsl:choose>
    <xsl:when test="$amounts">
      <xsl:call-template name="sumAmounts">
        <xsl:with-param name="amounts"
                        select="$amounts[position() > 1]" />
        <xsl:with-param name="subtotal"
          select="$subtotal + translate($amounts[1], ',', '')" />
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$subtotal" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>
  
I hope that helps,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread