Search code examples
xsltgroupingxslt-2.0xslt-grouping

xslt 2.0 multiple grouping


My Question: How can I apply double (or multiple) grouping?

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

Expected results in this case are 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">

So how can I apply double (or multiple) grouping?


Solution

  • 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.