Question

I am stuck with a problem which seems stupid but I cannot find out the solution... With XLST, I need to sum a list of values calculated by a template. So I stored these values in a tree structure (a list of "Number" elements contained in a root element "Numbers"). But whatever I try to do with this self-made list, it will return either nothing, 0 or an error...

Does someone know what I am doing wrong ?

<!-- create the tree fragment -->
<xsl:variable name="_subTotals">
    <Numbers>
        <xsl:for-each select="List">
            <xsl:variable name="_Size">
                <xsl:call-template name="GetSize">
                    <xsl:with-param name="_value" select="@value"/>
                </xsl:call-template>
            </xsl:variable>
            <Number>
                <xsl:value-of select="$_Size"/>
            </Number>
        </xsl:for-each>
    </Numbers>
</xsl:variable>

<!-- this returns an error: expression must result into a node-set -->
<xsl:message terminate="no">
    <xsl:value-of select="sum($_subTotals/Numbers/Number)"/>
</xsl:message>

<!-- transform the tree fragment into a node-set
<xsl:variable name="_Total" select="msxsl:node-set($_subTotals)"/>

<!-- returns nothing -->
<xsl:for-each select="$_Total/Numbers/Number">
    <xsl:message terminate="no">
        <xsl:value-of select="@value"/>
    </xsl:message>
</xsl:for-each>

<!-- returns 0 -->
<xsl:value-of select="sum($_Total/Numbers/Number)"/>
Was it helpful?

Solution

Here is a quick way how to sum dynamically-generated values (Probably the template you are calling is not producing the expected results? If so, you must ask another question and provide both the code and the XML document on which the code operates. Without these no one can help and guesses would not be useful.):

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common"
 >
 <xsl:output method="text"/>

    <xsl:template match="/">
      <xsl:variable name="vrtfNums">
         <nums>
           <num>1</num>
           <num>2</num>
         </nums>
      </xsl:variable>

      <xsl:variable name="vNums" select="ext:node-set($vrtfNums)"/>

      <xsl:value-of select="sum($vNums/*/*)"/>
    </xsl:template>
</xsl:stylesheet>

When the above transformation is applied on any XML document (ignored), the wanted result is produced:

3

OTHER TIPS

Recursion is the usual answer in functional languages. Something like:

<xsl:template name='totalRest>
  <xsl:variable nane='sub'>
    <!-- Use for-each to set local new context node -->
    <xsl:for-each select='following::List[1]'>
      <xsl:call-template name='totalRest'/>
    </xsl:for-each>
  </xsl:variable>
  <xsl:variable name='this'>
    <xsl:call-template name="GetSize">
      <xsl:with-param name="_value" select="@value"/>
    </xsl:call-template>
  </xsl:variable>

  <xsl:value-of select='$sub+$this' />

</xsl:template>

Without knowing more of GetSize and the input document it is hard to be more specific about the right XPath to set the context node for the recursive call.

In my case I had exactly the same problem that sum($something/element) returned 0 and sum($something/*) returned the correct value.

My problem was caused by the following UBL Invoice stylesheet declaration:

xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"

After removing this line, sum($something/element) returned the correct value.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top