1
0
mirror of https://github.com/alexandrev/xslt-lab.git synced 2026-09-18 19:43:16 +00:00
Files
xslt-lab/site/content/xslt/functions/xsl-accumulator.md
T
alexandrev-tibco 53e90ef86e feat(blog): complete XSLT/XPath reference — 229 function pages
Full coverage of XSLT 1.0, 2.0 and 3.0 elements and XPath functions:
- 59 XSLT elements (xsl:stylesheet → xsl:use-accumulators)
- 170 XPath functions (1.0 node/string/numeric/boolean, 2.0 sequence/
  date/QName/string, 3.0 HOF/map/array/JSON/streaming)
Each page: description, parameters table, return value, 2 runnable
Saxon examples with input XML + stylesheet + output, notes, cross-links.
xsltCompletions.js: all 229 entries now have blogSlug for hover links.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-19 09:28:05 +02:00

5.0 KiB

title, description, date, version, versionLabel, category, syntax, tags
title description date version versionLabel category syntax tags
xsl:accumulator Declares a streaming accumulator that maintains a typed value updated by rules as nodes are processed, enabling stateful aggregation without multiple passes. 2026-04-18T00:00:00Z 3.0 XSLT 3.0 element <xsl:accumulator name="name" as="type" initial-value="expression" streamable="no">
xslt
reference
xslt3

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

Attribute Type Required Description
name QName Yes The accumulator name, used in accumulator-before() and accumulator-after().
as sequence type No Type of the accumulated value. Default item()*.
initial-value expression Yes Starting value before any node is processed.
streamable yes|no No Whether 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