26
Feb

Using XSLT 1.0 to summarize a node-set with comma separated values

Pure XSLT is very powerful but it definitely has its weaknesses (I’ve written about how to extend XSLT using mapping and BizTalk previously here) … One of those are handling numbers that uses a different decimal-separator than a point (“.”).

Take for example the XML below

<Prices>
  <Price>10,1</Price>
  <Price>10,2</Price>
  <Price>10,3</Price>
</Prices>

Just using the XSLT sum-function on these values will give us a “NaN” values. To solve it we’ll have to use recursion and something like in the sample below.

The sample will select the node-set to summarize and send it to the “SummarizePrice” template. It will then add the value for the first Price tag of the by transforming the comma to a point. It will then check if it’s the last value and if not use recursion to call into itself again with the next value. It will  keep adding to the total amount until it reaches the last value of the node set.

<xsl:template match="Prices">
  <xsl:call-template name="SummurizePrice">
    <xsl:with-param name="nodes" select="Price" />
  </xsl:call-template>
</xsl:template>

<xsl:template name="SummurizePrice">
  <xsl:param name="index" select="1" />
  <xsl:param name="nodes" />
  <xsl:param name="totalPrice" select="0" />

  <xsl:variable name="currentPrice" select="translate($nodes[$index], ',', '.')"/>

  <xsl:choose>
    <xsl:when test="$index=count($nodes)">
      <xsl:value-of select="$totalPrice + $currentPrice"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:call-template name="SummurizePrice">
        <xsl:with-param name="index" select="$index + 1" />
        <xsl:with-param name="totalPrice" select="$totalPrice + $currentPrice" />
        <xsl:with-param name="nodes" select="$nodes" />
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>

</xsl:template>

Simple but a bit messy and nice to have for future cut and paste ;)

There's 5 Comments So Far

  • Viridovix
    July 13th, 2010 at 5:59 pm

    This works with XSLT 2.0 too. You only need to apply a type conversion for currentPrice: replace row 12 with this one:

  • Viridovix
    July 13th, 2010 at 6:01 pm

    LOL… sorry, the code was cutted out:

    select=”number(translate($nodes[$index], ‘,’, ‘.’))”

  • Stefan
    October 15th, 2010 at 9:59 am

    How about building a new nodeset?
    Something like:

    and then sum($pricelistwithdot) ?

  • Stefan
    October 15th, 2010 at 10:01 am

    Tags were stripped in my previous post :S. Maybe they are still available but just not shown?

  • Torbjörn
    December 7th, 2011 at 1:47 pm

    Thanks! Exactly what I needed.
    / TN

Share your thoughts, leave a comment!