xslt 2.0 multiple grouping

Tag: xslt , xslt-2.0 Author: quninging Date: 2013-10-14

Here is the source XML

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root>
    <row>
        <Type>1</Type>
        <WeaNr>100519</WeaNr>
    </row>
    <row>
        <Type>2</Type>
        <WeaNr>100519</WeaNr>
        <ETADC_SKU>2007925</ETADC_SKU>
        <CrossDock>N</CrossDock>
    </row>
    <row>
        <Type>2</Type>
        <WeaNr>100519</WeaNr>
        <ETADC_SKU>12007925</ETADC_SKU>
        <CrossDock>N</CrossDock>
    </row>
    <row>
        <Type>2</Type>
        <WeaNr>100519</WeaNr>
        <ETADC_SKU>200792ww5</ETADC_SKU>
        <CrossDock>Y</CrossDock>
    </row>
    <row>
        <Type>1</Type>
        <WeaNr>100520</WeaNr>
    </row>
    <row>
        <Type>2</Type>
        <WeaNr>100520</WeaNr>
        <ETADC_SKU>2007925444</ETADC_SKU>
        <CrossDock>N</CrossDock>
    </row>
    <row>
        <Type>2</Type>
        <WeaNr>100520</WeaNr>
        <ETADC_SKU>2007925333</ETADC_SKU>
        <CrossDock>Y</CrossDock>
    </row>
    <row>
        <Type>2</Type>
        <WeaNr>100520</WeaNr>
        <ETADC_SKU>204445333</ETADC_SKU>
        <CrossDock>Y</CrossDock>
    </row>
</root>

I want use grouping by WeaNr and CrossDock

For example in this case I will have 4 groups:

1. WeaNr=100519 and CrossDock=N
2. WeaNr=100519 and CrossDock=Y
3. WeaNr=100520 and CrossDock=N
4. WeaNr=100520 and CrossDock=Y

Grouping just by one field, like WeaNr is easy:

<xsl:for-each-group select="row" group-by="WeaNr">

but I don't know how to make double grouping

Best Answer

You would group-by some string that is a combination of the two, for example

<xsl:for-each-group select="row" group-by="concat(WeaNr, '|', CrossDock)">

or alternatively use two nested levels of for-each-group

<xsl:for-each-group select="row" group-by="WeaNr">
  <xsl:for-each-group select="current-group()" group-by="CrossDock">

The difference between these two approaches is apparent if you use the position() function in the body of the for-each-group - in the concat case you'll get position values from 1 to 4, in the nested case you'll get 1, 2, 1, 2 (because the position() is determined by the nearest enclosing for-each-group). Similarly, last() will be 4 in the concat case and 2 in the nested case.

comments:

Also, of course, current-grouping-key() will be different in the two cases.