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-for-each-group.md
T
alexandrev-tibco b9d58ff7e0 feat(blog): XSLT/XPath function reference section (Phase 2)
- 19 reference pages under /xslt/functions/ covering:
  xsl:value-of, xsl:for-each, xsl:for-each-group, xsl:function,
  xsl:iterate, last(), position(), count(), concat(), contains(),
  substring(), sum(), key(), current(), string-join(), tokenize(),
  matches(), replace(), format-date()
- Each page: description, parameters table, return value, 2 runnable
  examples (input XML + stylesheet + output), notes, cross-links
- New Hugo section with reference-specific layout (version badges,
  syntax block, "Try in Playground" CTA, parameters table styles)
- Menu entry "Reference" → /xslt/functions/
- CSS: .ref-badge, .ref-syntax, .ref-index-list, .ref-try + table styles

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 14:38:55 +02:00

4.8 KiB

title, description, date, version, versionLabel, category, syntax, tags
title description date version versionLabel category syntax tags
xsl:for-each-group Groups a sequence of items by a key expression or adjacent values, then iterates over each distinct group. 2026-04-18T00:00:00Z 2.0 XSLT 2.0 element <xsl:for-each-group select="sequence" group-by="expression">
xslt
reference
xslt2

Description

xsl:for-each-group divides a sequence into groups and then processes each group once. It replaces the complex Muenchian grouping technique required in XSLT 1.0 with a clean, declarative approach.

There are four mutually exclusive grouping attributes:

  • group-by — groups items that share the same value of the key expression (like SQL GROUP BY).
  • group-adjacent — groups consecutive items with the same key value.
  • group-starting-with — starts a new group whenever an item matches a pattern.
  • group-ending-with — ends the current group whenever an item matches a pattern.

Inside the loop body, current-group() returns the sequence of items in the current group, and current-grouping-key() returns the key value that defines the group (available with group-by and group-adjacent).

Parameters

Parameter Type Required Description
select XPath expression Yes The sequence to be grouped.
group-by XPath expression No* Key expression evaluated for each item; items with equal keys form a group.
group-adjacent XPath expression No* Like group-by but only consecutive equal-key items are grouped.
group-starting-with Pattern No* A new group begins each time an item matches the pattern.
group-ending-with Pattern No* A group ends each time an item matches the pattern.
collation URI No Collation used for key comparison.

*Exactly one grouping attribute must be present.

Examples

Group items by category

Input XML:

<?xml version="1.0" encoding="UTF-8"?>
<products>
  <product><name>Apple</name><category>Fruit</category></product>
  <product><name>Carrot</name><category>Vegetable</category></product>
  <product><name>Banana</name><category>Fruit</category></product>
  <product><name>Broccoli</name><category>Vegetable</category></product>
  <product><name>Cherry</name><category>Fruit</category></product>
</products>

Stylesheet:

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

  <xsl:template match="/products">
    <grouped>
      <xsl:for-each-group select="product" group-by="category">
        <xsl:sort select="current-grouping-key()"/>
        <group name="{current-grouping-key()}">
          <xsl:for-each select="current-group()">
            <item><xsl:value-of select="name"/></item>
          </xsl:for-each>
        </group>
      </xsl:for-each-group>
    </grouped>
  </xsl:template>
</xsl:stylesheet>

Output:

<grouped>
  <group name="Fruit">
    <item>Apple</item>
    <item>Banana</item>
    <item>Cherry</item>
  </group>
  <group name="Vegetable">
    <item>Carrot</item>
    <item>Broccoli</item>
  </group>
</grouped>

Group adjacent elements (section headings)

Input XML:

<?xml version="1.0" encoding="UTF-8"?>
<doc>
  <h1>Introduction</h1>
  <p>First paragraph.</p>
  <p>Second paragraph.</p>
  <h1>Conclusion</h1>
  <p>Final paragraph.</p>
</doc>

Stylesheet:

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

  <xsl:template match="/doc">
    <sections>
      <xsl:for-each-group select="*" group-starting-with="h1">
        <section>
          <title><xsl:value-of select="self::h1"/></title>
          <xsl:for-each select="current-group()[not(self::h1)]">
            <para><xsl:value-of select="."/></para>
          </xsl:for-each>
        </section>
      </xsl:for-each-group>
    </sections>
  </xsl:template>
</xsl:stylesheet>

Output:

<sections>
  <section>
    <title>Introduction</title>
    <para>First paragraph.</para>
    <para>Second paragraph.</para>
  </section>
  <section>
    <title>Conclusion</title>
    <para>Final paragraph.</para>
  </section>
</sections>

Notes

  • current-group() is only accessible inside the body of xsl:for-each-group.
  • xsl:sort applies to the order of groups, not to the items within each group. Sort items inside xsl:for-each select="current-group()" separately.
  • Multiple grouping keys can be achieved by nesting xsl:for-each-group elements.
  • For XSLT 1.0, the equivalent technique is the Muenchian method using xsl:key and generate-id(). See the XSLT grouping guide.

See also