Questions tagged [xslt-grouping]

Grouping mechanisms that are specific to XSLT. Should always be complemented with either the xslt-1.0, xslt-2.0 or xslt-3.0 tag to indicate the version used.

Grouping in XSLT 3

Grouping in XSLT 3, the current and latest version of XSLT since 2017, can be achieved primarily using the xsl:for-each-group instruction where you select the items to be grouped, the grouping population, with the select attribute and then have three different ways to group the population:

  1. the group-by attribute selecting a sequence of grouping keys by which the grouping population is to be grouped
  2. the group-adjacent attribute selecting a sequence of grouping keys by which adjacent items in the population are to be grouped
  3. the group-starting-with or group-ending-with attributes defining patterns to identify and start groups based on pattern matching of the initial (group-starting-with) or final (group-ending-with) member of a group

Access to the items of a currently processed group is given by the current-group() function, access to the current grouping key by the current-grouping-key() function.

The XSLT 3 specification gives at least one example for each grouping approach directly in the specification section https://www.w3.org/TR/xslt-30/#grouping-examples; below you find links to XSLT fiddles based on these examples:

Of course the different approaches can, for more complex tasks, be combined by nesting xsl:for-each-group instructions.

XSLT 3 with XPath 3.1 support can also group JSON represented as XPath 3.1 maps and arrays, here is a list of showing the previous XML grouping samples now using JSON input and directly grouping the map/array data structure returned by the parse-json function:

Positional grouping

Positional grouping can be used to split a sequence of items into groups of a certain size; in XSLT 2 or 3 this is easily achieved using e.g. for-each-group select="foo" group-adjacent="(position() - 1) idiv $chunk-size": https://xsltfiddle.liberty-development.net/asoTK9

https://martin-honnen.github.io/xslt/generic-positional-grouping-functions.xsl is a compact XSLT 3 module using higher-order functions importable by other code that needs to split up a sequence of items using positional grouping, you could use it as follows (Saxon-JS 2, Saxon 10 or higher all editions, Saxon 9.8 or higher PE and EE, Altova XML 2017 R3 or later)

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="3.0"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    xmlns:ex="http://example.com/ex"
    exclude-result-prefixes="#all"
    expand-text="yes">

  <xsl:import href="https://martin-honnen.github.io/xslt/generic-positional-grouping-functions.xsl"/>

  <xsl:function name="ex:wrap-rows" as="element()">
    <xsl:param name="group" as="item()*"/>
    <xsl:param name="pos" as="xs:integer"/>
    <xsl:param name="wrapper-name" as="xs:QName"/>
    <xsl:element name="{$wrapper-name}" namespace="{namespace-uri-from-QName($wrapper-name)}">
      <xsl:attribute name="index" select="$pos"/>
      <xsl:sequence select="$group"/>
    </xsl:element>
  </xsl:function>

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="root">
    <root>
      <xsl:sequence select="mf:group-chunks(item, 3, ex:wrap-rows(?, ?, QName('', 'chunk')))"/>
    </root>
  </xsl:template>

  <xsl:template match="/">
    <xsl:next-match/>
    <xsl:comment>Run with {system-property('xsl:product-name')} {system-property('xsl:product-version')} {system-property('Q{http://saxon.sf.net/}platform')}</xsl:comment>
  </xsl:template>

</xsl:stylesheet>

to e.g. wrap any chunk into a container element.

Grouping in XSLT 2

Grouping in XSLT 2 also works with the xsl:for-each-group instruction as in XSLT 3, the main restrictions are that XSLT 2 does not support composite grouping keys (so to group on various items you need to concat or string-join them as single value (e.g. composite="yes" group-by="foo, bar" in XSLT 3 needs to be done as group-by="string-join((foo, bar), '|')")) and that pattern matching can only be done on nodes, not on primitive values.

The XSLT 2 specification gives at least one example for each grouping approach directly in the specification section https://www.w3.org/TR/xslt20/#grouping-examples; below you find links to XSLT fiddles based on these examples:

Grouping in XSLT 1.0

The preferred solution in XSLT 1.0 is to use the Muenchian grouping method:
http://www.jenitennison.com/xslt/grouping/muenchian.html

552 questions
13
votes
4 answers

How to count distinct values in a node?

How to count distinct values in a node in XSLT? Example: I want to count the number of existing countries in Country nodes, in this case, it would be 3. 62
Daniel Silveira
  • 41,125
  • 36
  • 100
  • 121
10
votes
2 answers

XSLT Sorting - how to sort xml childnodes inside a parent node with an attribute

What started out as a simple thing has turned out quite troublesome for XSLT noob. Trying to sort childnodes/descending but, after adding an attribute to their parent node, I receive an error when debugging in VS2010: "Attribute and namespace nodes…
JimXC
  • 275
  • 1
  • 4
  • 12
6
votes
1 answer

xslt 2.0 multiple grouping

My Question: How can I apply double (or multiple) grouping? Here is the source XML: 1 100519
VextoR
  • 5,087
  • 22
  • 74
  • 109
5
votes
2 answers

Grouping on elements in XML transformation with XSLT

I am struggling with the concept of grouping (on multiple keys) of table based XML to hierarchy with XSLT The grouping is based on first four elements, however the grouping must break if there is another element in between the set. Source…
ggonsalv
  • 1,264
  • 8
  • 18
5
votes
2 answers

Is the [1] in Muenchian grouping really necessary?

Having answered a large number of XSLT questions here on Stack Overflow, I am more than familiar with the Muenchian grouping technique for grouping nodes during an XSL transformation. The expression used therein is usually something like…
JLRishe
  • 99,490
  • 19
  • 131
  • 169
4
votes
1 answer

Grouping section of xml

I'm having some problems grouping a part of an input tree into a container element and leaving other parts intact. I am trying to use the for-each-group as an exercise. Logic: Process elements with template matches and try to detect when an element…
Zug_Bug
  • 186
  • 10
4
votes
4 answers

XSL to create nested list from flat tree problem

I need to be able to create nested lists from a flat tree. For example, the input might be something like this:

text

num1 num2 sub-num1
Jacqueline
  • 193
  • 1
  • 15
4
votes
1 answer

XSLT Muenchian grouping from BizTalk WCF-SQL Adapter Schema by ID across groups

I am working on a BizTalk application that performs typed polling from a database using the WCF SQL adapter. After researching how to group data from the generated schema to my canonical schema, I came across Muenchian Grouping as the common…
4
votes
2 answers

How do we identify a set of nodes and add that set into another where the structure of XML source vary in XSLT?

I'm trying to convert Flash based Text format into HTML based text. There are
  • blocks in the source xml i need to add adjacent
  • block inside a
      block.

    • ------
    • | - should be wrapped with
  • tymspy
    • 4,200
    • 2
    • 20
    • 35
    4
    votes
    2 answers

    Group Adjacent Functionality in XSLT

    I have a question about the use of group-adjacent. I have seen two patterns being used: Pattern 1: Pattern 2:
    3
    votes
    2 answers

    XSLT 1.0 grouping using keys based on attribute in parent

    Using XSLT 1.0 I need to transform this:
    Colors red orange yellow green blue indigo
    devjeff
    • 153
    • 1
    • 4
    3
    votes
    1 answer

    How to transform xml to sql query using XSLT?

    I have an xml file and i want to create sql query from it. like below OUTPUT NEEDED: INSERT INTO 'table' values ('2','0','SUGAR_QTY','2','2') ('2','0','OIL_QTY','5','1') 2
    madhu madi
    • 85
    • 8
    3
    votes
    1 answer
    3
    votes
    1 answer

    XSLT 3.0 Streaming with Grouping and Sum/Accumulator

    I'm trying to figure out how to use XSLT Streaming (to reduce memory usage) in a scenario that requires grouping (with an arbitrary number of groups) and summing the group. So far I haven't been able to find any examples. Here's an example…
    RyanB
    • 757
    • 4
    • 11
    3
    votes
    1 answer

    Uniformly process grouped sibling elements

    Given the following XML document
    kostix
    • 51,517
    • 14
    • 93
    • 176
    1
    2 3
    36 37