Re: [xsl] How do I get a SUM of the string-length of all child nodes ??

Subject: Re: [xsl] How do I get a SUM of the string-length of all child nodes ??
From: Dimitre Novatchev <dnovatchev@xxxxxxxxx>
Date: Sun, 29 May 2005 11:48:17 +1000
Assuming we want to get the sum of string-lengths of all child nodes
of the top node,

using FXSL one would write:

           sum(f:map(f:string-length(), /*/node()))

Here's a complete transformation:


<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
xmlns:xs="http://www.w3.org/2001/XMLSchema";
xmlns:f="http://fxsl.sf.net/";
exclude-result-prefixes="f xs"
>
   <xsl:import href="../f/func-map.xsl"/>
   <xsl:import href="../f/func-Operators.xsl"/>
   <xsl:import href="../f/func-standardXpathFunctions.xsl"/>

<!--
    This transformation must be applied to:
        ../data/numList.xml

        Expected result: 20
-->

   <xsl:strip-space elements="*"/>

   <xsl:output omit-xml-declaration="yes" indent="yes"/>
   <xsl:strip-space elements="*"/>

   <xsl:template match="/">
     <xsl:value-of select="sum(f:map(f:string-length(), /*/node()))"/>
   </xsl:template>
</xsl:stylesheet>


When applied for example on this source.xml file:

<nums>
  <num>01</num>
  <num>02</num>
  <num>03</num>
  <num>04</num>
  <num>05</num>
  <num>06</num>
  <num>07</num>
  <num>08</num>
  <num>09</num>
  <num>10</num>
</nums>

the wanted result is produced:

   20

One can use also the transform-and-sum template (FXSL for XSLT 1.0) or
the f:transform-and-sum() function (FXSL for XSLT 2.0). In the last
case the necessary XPath expression is:

   f:transform-and-sum(f:string-length(), /*/*)

and the complete transformation:

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
xmlns:f="http://fxsl.sf.net/";
exclude-result-prefixes="f"
>
   <xsl:import href="../f/func-transform-and-sum.xsl"/>
   <xsl:import href="../f/func-standardXpathFunctions.xsl"/>

   <!-- to be applied on numList.xml -->

   <xsl:output method="text"/>

    <xsl:template match="/">
      <xsl:value-of select=
      "f:transform-and-sum(f:string-length(), /*/*)"/>
    </xsl:template>
</xsl:stylesheet>


Cheers,
Dimitre Novatchev.

On 5/27/05, Michael Kay <mike@xxxxxxxxxxxx> wrote:
> In XSLT 1.0 the sum() function can only sum the string values of nodes, it
> can't sum a set of computed numbers. This means your options are
>
> (a) a two-phase transformation: first create a tree in which the computed
> numbers are represented as attributes (typically), then sum over these
> attributes
>
> (b) a recursive template to compute the sum
>
> In 2.0, like many things, it's much easier:
>
>    sum(child::node()/string-length())
>
> Michael Kay
> http://www.saxonica.com/
>
>
> > -----Original Message-----
> > From: Bovy, Stephen J [mailto:STEPHEN.Bovy@xxxxxx]
> > Sent: 27 May 2005 07:36
> > To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
> > Subject: [xsl] How do I get a SUM of the string-length of all
> > child nodes ??
> >
> > I am not sure how to do this:
> >
> > here is what I have which is obviously incorrect:
> >
> > <xsl:template match="/*/*/*" >
> >   <xsl:param name="rcnt" />
> >   <xsl:choose>
> >   <xsl:when test="position()=1">
> >     <xsl:variable name="csum" select="sum(string-length(.))"/>
> > rsizes <xsl:value-of select="$rcnt"/> =<xsl:value-of select="$csum"/>;
> >   </xsl:when>
> >   <xsl:otherwise>
> >   bt('<td align="center"> ');
> >   bt('<xsl:value-of select="."/> ');
> >   bt('</td> ');
> >   </xsl:otherwise>
> >   </xsl:choose>
> > </xsl:template>

Current Thread