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
0
votes
1 answer

Getting error when run the build.xml in Cakuban project

We planed to use Cakupan (Link) as the XSLT unit test coverage tool. We have downloaded the sample project and ran the build.xml. At that time we are betting the bellow error. C:\Cakupan\build.xml:143: java.lang.NoClassDefFoundError:…
Java-Seekar
  • 1,720
  • 5
  • 30
  • 52
0
votes
1 answer

Sums and Category Grouping and sub Grouping with XSLT

With XSLT, how can I change the following:
0
votes
1 answer

XSLT sibling from grandparent level

I have an xml that looks like the following. I need to find all the distinct Currencies. Using the following
Adina
  • 3
  • 3
0
votes
1 answer

group an element using xslt

I want to use the function "group by" in a xsl file but I am just getting errors. This is my code:
Fran Rod
  • 586
  • 4
  • 14
  • 26
0
votes
2 answers

Trying to use XSLT to create HTML table from XML

I'm struggling with XSLT. I'm stuck in procedural land. Basically I have some XML that gets generated from a database that looks a bit like this:
Mark
  • 1,296
  • 13
  • 28
0
votes
2 answers

Using XSLT to wrap elements, but it is not including the last matching element

I'm trying to transform old XML files into a new and improved structure. Part of this needs me to wrap some loose elements into a parent container, as well as modify their children Old structure asdf
HorusKol
  • 8,375
  • 10
  • 51
  • 92
0
votes
1 answer

XSLT GROUP BY using keys

I am trying to generate HTML output that is a table on the following hierarchy - DIVISION,DESK,STRATEGY. I need to set rowspan on Division column and Desk column. One division can have multiple desks and one desk can have multiple strategies. I am…
0
votes
1 answer

XSLT 1.0 Find unique node with Highest value

I am beginner in XSLT 1.0. I am facing an issue when i tried to find unique node with Highest value. Source XML: A B
Ankur Raiyani
  • 1,509
  • 5
  • 21
  • 49
0
votes
2 answers

Populate Drop Down List with XML Node Distinct Values Only

I'm trying to produce a search filter that will work with an existing XML data file and I'm starting with trying to display just unique values from one of the nodes in a drop down list box. An example of the XML file can be seen…
user1503689
  • 169
  • 1
  • 3
  • 12
0
votes
1 answer

Javascript in XSLT

In XSLT, I have to assign some values to particular element and it should get print using Javascript. For example 123 is my input element data and I want to output in such a way that the element should display "123 3456" using Javascript code in…
0
votes
1 answer

How can I group nodes in xslt 1.0 by countable field?

I have an approximately this kind of xml: en-us Name in english
valerii.sverdlik
  • 559
  • 4
  • 18
0
votes
1 answer

XSLT 1.0 get node set

i am beginner in XSLT. I am using XSLT to transform XML to XML through JDK 6. Below is the Source XML which i received from the web service. Source XML: AA
Ankur Raiyani
  • 1,509
  • 5
  • 21
  • 49
0
votes
1 answer

XSLT 1.0 calculation with grouping

I am beginner in XSLT and using it to transform XML to XML through Java. Source XML:
Ankur Raiyani
  • 1,509
  • 5
  • 21
  • 49
0
votes
1 answer

Merging tags based on two different complex tags

In the below two ASNInPO's po_nbr is same container_id under ASNInCtn is same and item_id under ASNInItem is different. In this case two ASNInPO's has to be merged and two ASNInCtn's has to be merged into one tag. This is my Input:
0
votes
1 answer

Testing for 2 conditions under group-starting-with in

I need to test for 1 of 2 possible tags in a for-each-group. Is this possible? What is the correct syntax? I tried "||" but got an error from the parser. I'm using Saxon PE 9.3 in Oxygen 12.1. Ex.
Jeff
  • 877
  • 2
  • 11
  • 17
A B