xsltloopsmuenchian-grouping

XSLT Loop - Four nodes at a time


Firstly I am aware of this question: XSLT: Loop selecting two elements at a time

However I have not found it to work due to the element structure or I just fail with using mod, one of the two.

<input>
  <node>
    <id>1</id>
    <value>3</value>
  </node>
  <node>
    <id>1</id>
    <value>3</value>
  </node>
  <node>
    <id>1</id>
    <value>3</value>
  </node>
  <node>
    <id>1</id>
    <value>3</value>
  </node>
  <node>
    <id>2</id>
    <value>4</value>
  </node>
  <node>
    <id>2</id>
    <value>4</value>
  </node>
  <node>
    <id>2</id>
    <value>4</value>
  </node>
  <node>
    <id>2</id>
    <value>4</value>
  </node>
</input>

I have the following layout of XML which has the following structure: - Nodes of the same ID will ALWAYS be grouped together - There will always be four nodes to one ID

I wish to be able to select the four nodes of one ID at a time and loop through each group of four, so that I can manipulate the data into one output line.

What would be the best way to approach this?


Solution

  • This XSLT:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    
    <xsl:key name="keyByID" match="node" use="id"/>
    
    <xsl:template match="/">
        <output>
            <xsl:apply-templates/>
        </output>
    </xsl:template>
    
    <xsl:template match="input">
        <xsl:for-each select="node[generate-id()=generate-id(key('keyByID',id)[1])]">
            <block>
                <id>
                    <xsl:value-of select="id"/>
                </id>
                <value>
                    <xsl:value-of select="value"/>
                </value>
            </block>
        </xsl:for-each>
    </xsl:template>
    
    
    </xsl:stylesheet>
    

    applied to your Input XML:

    <?xml version="1.0" encoding="UTF-8"?>
    <input>
    <node>
        <id>1</id>
        <value>3</value>
    </node>
    <node>
        <id>1</id>
        <value>3</value>
    </node>
    <node>
        <id>1</id>
        <value>3</value>
    </node>
    <node>
        <id>1</id>
        <value>3</value>
    </node>
    <node>
        <id>2</id>
        <value>4</value>
    </node>
    <node>
        <id>2</id>
        <value>4</value>
    </node>
    <node>
        <id>2</id>
        <value>4</value>
    </node>
    <node>
        <id>2</id>
        <value>4</value>
    </node>
    </input>
    

    gives this grouped Output XML:

    <?xml version="1.0" encoding="UTF-8"?>
    <output>
    <block>
        <id>1</id>
        <value>3</value>
    </block>
    <block>
        <id>2</id>
        <value>4</value>
    </block>
    </output>
    

    The output is grouped by <id>. Is that what you are looking for? I am not sure. This Muenchian Grouping just simpliefies your structure.