Sponsored

XSLT Reference

xsl:accumulator

XSLT 3.0 element

Declares a streaming accumulator that maintains a typed value updated by rules as nodes are processed, enabling stateful aggregation without multiple passes.

Syntax
<xsl:accumulator name="name" as="type" initial-value="expression" streamable="no">

Description

xsl:accumulator solves one of the hardest problems in streaming XSLT: maintaining state as nodes flow past the processor. In a non-streaming stylesheet you can freely look up ancestors, siblings, and preceding elements. In streaming mode, once a node has been processed it is gone. Accumulators bridge this gap by keeping a running value that is updated automatically as the processor enters and exits matched nodes.

An accumulator is declared as a top-level element with a name, an XPath as type, and an initial-value. One or more xsl:accumulator-rule children define the update logic for specific node patterns. Rules fire in document order: a phase="start" rule fires when the processor encounters the opening tag; phase="end" fires when the closing tag is reached.

To read an accumulator’s value at any point, use the XPath functions accumulator-before('name') (the value before the current node was processed) or accumulator-after('name') (the value after the current node and all its descendants were processed).

Accumulators must be declared in scope for any mode that uses them via xsl:use-accumulators on the mode or use-accumulators on xsl:stream. They are essentially a functional equivalent of mutable global state, but safe for streaming because the processor manages the update lifecycle.

Attributes

AttributeTypeRequiredDescription
nameQNameYesThe accumulator name, used in accumulator-before() and accumulator-after().
assequence typeNoType of the accumulated value. Default item()*.
initial-valueexpressionYesStarting value before any node is processed.
streamableyes|noNoWhether the accumulator rules must be streamable. Default no.

Examples

Tracking the current section heading while streaming

Input XML:

<?xml version="1.0" encoding="UTF-8"?>
<document>
  <section title="Introduction">
    <para>First paragraph.</para>
    <para>Second paragraph.</para>
  </section>
  <section title="Methods">
    <para>Third paragraph.</para>
  </section>
</document>

Stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xsl:output method="xml" indent="yes"/>

  <xsl:accumulator name="current-section" as="xs:string" initial-value="''">
    <xsl:accumulator-rule match="section" phase="start"
      select="string(@title)"/>
    <xsl:accumulator-rule match="section" phase="end"
      select="''"/>
  </xsl:accumulator>

  <xsl:mode use-accumulators="current-section"/>

  <xsl:template match="/document">
    <result>
      <xsl:apply-templates select="section/para"/>
    </result>
  </xsl:template>

  <xsl:template match="para">
    <item section="{accumulator-before('current-section')}">
      <xsl:value-of select="."/>
    </item>
  </xsl:template>
</xsl:stylesheet>

Output:

<result>
  <item section="Introduction">First paragraph.</item>
  <item section="Introduction">Second paragraph.</item>
  <item section="Methods">Third paragraph.</item>
</result>

Running total accumulator

Stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xsl:output method="xml" indent="yes"/>

  <xsl:accumulator name="running-total" as="xs:decimal"
    initial-value="xs:decimal(0)" streamable="yes">
    <xsl:accumulator-rule match="order" phase="end"
      select="$value + xs:decimal(@amount)"/>
  </xsl:accumulator>

  <xsl:mode streamable="yes" use-accumulators="running-total"/>

  <xsl:template match="/">
    <xsl:stream href="orders.xml">
      <xsl:apply-templates/>
    </xsl:stream>
  </xsl:template>

  <xsl:template match="orders">
    <summary>
      <total><xsl:value-of select="accumulator-after('running-total')"/></total>
    </summary>
  </xsl:template>
</xsl:stylesheet>

Notes

  • The variable $value inside xsl:accumulator-rule refers to the current accumulator value before the rule fires.
  • Accumulators are scoped to the document being processed. When you call doc(), the accumulator is re-initialised for that document.
  • Multiple accumulators can be active simultaneously on the same mode.
  • streamable="yes" requires each rule’s select to be a streamable expression.

See also