Search code examples
xsltxslt-2.0xslt-grouping

XSLT - Split node and group items


I'm new to XSLT and challenging the following requirement:

source:

<item>
  <name>123-foo</name>
  <value>xxx</value>
</item>
<item>
  <name>123-bar</name>
  <value>yyy</value>
</item>
<item>
  <name>456-foo</name>
  <value>zzz</value>
</item>
<item>
  <name>456-bar</name>
  <value>aaa</value>
</item>

Should result in something like this:

<item>
  <key>123</key>
  <control>foo</control>
  <value>xxx</value>
</item>
<item>
  <key>123</key>
  <control>bar</control>
  <value>yyy</value>
</item>
<item>
  <key>456</key>
  <control>foo</control>
  <value>zzz</value>
</item>
<item>
  <key>456</key>
  <control>bar</control>
  <value>aaa</value>
</item>

Additional requirement: The first two items of the list should be skipped.

In a second step these items should be grouped by key.

<xsl:for-each-group select="*" group-by="key"> 
 <!-- do something with each grouped item -->
</xsl:for-each-group> 

How can I achieve this? I already have a variable named $data to get the value of each source item. Example: <xsl:value-of select="$data/123-foo"></xsl:value-of> will have the output "xxx" but I'm not sure if this will help.


Solution

  • You can do it in one step:

        <xsl:for-each-group select="item" group-by="substring-before(name, '-')"> 
            <group>
                <xsl:for-each select="current-group()"> 
                    <item>
                        <key>
                            <xsl:value-of select="current-grouping-key()"/>
                        </key>
                        <control>
                            <xsl:value-of select="substring-after(name, '-')"/>
                        </control>
                        <xsl:copy-of select="value"/>
                    </item>
                </xsl:for-each>
            </group>
        </xsl:for-each-group>
    

    Demo: https://xsltfiddle.liberty-development.net/gVAkJ5m

    Not sure what you mean by:

    The first two items of the list should be skipped.