Search code examples
xsltxslt-1.0xslt-grouping

How to group nearby same elements using XSLT version 1


I need to transform an XML structure to another XML structure by grouping nearby elements using XSLT version 1 and store into a variable for later process.

My current solution: https://xsltfiddle.liberty-development.net/naZXVF1/3

XML

<?xml version="1.0"?>
 <Items>
      <Parameter>1</Parameter>
      <Parameter>2</Parameter>
      <Menu>1</Menu>
      <Parameter>3</Parameter>
      <Parameter>4</Parameter>
      <Menu>2</Menu>
      <Menu>3</Menu>
      <Parameter>5</Parameter>
      <Parameter>6</Parameter>
      <Parameter>7</Parameter>
      <Parameter>8</Parameter>
  </Items>

Expected Result

<Items>
   <Parameters>
      <Parameter>1</Parameter>
      <Parameter>2</Parameter>
   </Parameters>
   <Menus>
     <Menu>1</Menu>
   </Menus>  
   ...
</Items>

Solution

  • Either use sibling recursion or use a complicated key to identify the elements belonging together:

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0" 
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
      <xsl:output indent="yes"/>
    
      <xsl:key name="group" match="*[name(preceding-sibling::*[1]) = name()]"
        use="generate-id(preceding-sibling::*[name() = name(current())][name(preceding-sibling::*[1]) != name()][1])"/>
    
      <xsl:template match="Items">
          <xsl:copy>
              <xsl:apply-templates select="*[name(preceding-sibling::*[1]) != name()]"/>
          </xsl:copy>
      </xsl:template>
    
      <xsl:template match="Items/*">
          <xsl:element name="{name()}s">
              <xsl:copy-of
                select=". | key('group', generate-id())"/>
          </xsl:element>
      </xsl:template>
    </xsl:stylesheet>
    

    https://xsltfiddle.liberty-development.net/naZXVF1/4