Computing Sums and Products

Problem

You need to sum or multiply functions of numbers contained in a node set.

Solution

The abstract form of sum for processors that support tail-recursive optimization is as follows:

<xsl:template name="math:sum">
  <!-- Initialize nodes to empty node set -->
  <xsl:param name="nodes" select="/.."/>
  <xsl:param name="result" select="0"/>
  <xsl:choose>
    <xsl:when test="not($nodes)">
      <xsl:value-of select="$result"/>
    </xsl:when>
    <xsl:otherwise>
        <!-- call or apply template that will determine value of node 
          unless the node is literally the value to be summed -->
      <xsl:variable name="value">
        <xsl:call-template name="some-function-of-a-node">
          <xsl:with-param name="node" select="$nodes[1]"/>
        </xsl:call-template>
      </xsl:variable>
       <!-- recurse to sum rest -->
      <xsl:call-template name="math:sum">
        <xsl:with-param name="nodes" select="$nodes[position(  ) != 1]"/>
        <xsl:with-param name="result" select="$result + $value"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Two techniques can handle a large number of nodes in the absence of tail-recursive optimization. The first is commonly called divide and conquer. The idea behind this technique is to reduce the amount of work by at least a factor of two on each recursive step:

<xsl:template name="math:sum-dvc"> <xsl:param name="nodes" select="/.."/> <xsl:param name="result" select="0"/> <xsl:param name="dvc-threshold" select="100"/> <xsl:choose> <xsl:when test="count($nodes) &lt;= $dvc-threshold"> <xsl:call-template ...

Get XSLT Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.