Difference in XSLT Grouping Attributes?
XSLT 2.0 introduced the <xsl:for-each-group>
instruction to simplify complex grouping tasks that previously required
verbose Muenchian grouping techniques in XSLT 1.0. The element provides
several distinct attributes to control grouping logic, most notably
group-by, group-adjacent, and
group-starting-with (along with its counterpart
group-ending-with). While all three attributes organize an
input sequence into distinct collections processed via
current-group() and current-grouping-key(),
they differ fundamentally in whether they evaluate items based on global
value equality, sequential runs of identical values, or positional
patterns within the document structure.
group-by:
Value-Based Global Grouping
The group-by attribute groups items by evaluating a key
expression for each item across the entire sequence. All items that
evaluate to the same key value are placed into the same group,
regardless of where they appear in the original source document.
- Evaluation: Evaluates the expression for every item
in
select. - Ordering: Creates one group per distinct key. The order of the groups corresponds to the first appearance of each key in the source sequence.
- Use Case: Aggregating data, such as organizing a flat list of products by category or department.
<xsl:for-each-group select="employee" group-by="department">
<department name="{current-grouping-key()}">
<xsl:copy-of select="current-group()"/>
</department>
</xsl:for-each-group>group-adjacent:
Consecutive Value Grouping
The group-adjacent attribute forms groups strictly from
contiguous sequences of items that share the exact same key value. If an
item has a different key value than its predecessor, a new group starts
immediately, even if that key value appeared earlier in the
sequence.
- Evaluation: Compares each item's key expression only to the adjacent item.
- Ordering: Maintains strict document order; non-consecutive items with identical keys will end up in separate groups.
- Use Case: Wrapping consecutive elements of the same type, such as grouping runs of standard text nodes or adjacent list items within mixed content.
<xsl:for-each-group select="*" group-adjacent="boolean(self::li)">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<ul>
<xsl:copy-of select="current-group()"/>
</ul>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>group-starting-with:
Pattern-Based Structural Grouping
The group-starting-with attribute uses a pattern
(similar to an xsl:template match="..." pattern) rather
than an expression. A new group begins whenever an item matches the
specified pattern, and that matched item becomes the first element in
the new group. All subsequent items belong to this group until another
matching item appears.
- Evaluation: Evaluates whether each item matches an XSLT pattern.
- Grouping Key: Does not generate a grouping key;
current-grouping-key()evaluates to an empty sequence. - Use Case: Restructuring flat document formats into
hierarchical structures, such as gathering flat paragraphs under heading
tags (
h1,h2, etc.).
<xsl:for-each-group select="*" group-starting-with="h2">
<section>
<xsl:copy-of select="current-group()"/>
</section>
</xsl:for-each-group>Comparison Summary
| Attribute | Mechanism | Handles Non-Adjacent Items | current-grouping-key() Available |
Primary Purpose |
|---|---|---|---|---|
group-by |
Expression evaluation | Yes (merges globally) | Yes | Categorizing and aggregating data |
group-adjacent |
Expression evaluation | No (splits on value change) | Yes | Grouping contiguous sequences |
group-starting-with |
Pattern matching | No (splits on pattern match) | No | Converting flat structures to hierarchies |