0
votes

I have the following input XML:

<?xml version="1.0" encoding="UTF-8"?>
<data>
    <row>
        <code>EXCLUDE</code>
        <value>VALUE1</value>
    </row>
    <row>
        <code>EXCLUDEALSO</code>
        <value>VALUE2</value>
    </row>
    <row>
        <code>NUMBER</code>
        <value>001</value>
    </row>
    <row>
        <code>FROM</code>
        <value>NAMELINE_FROM</value>
    </row>
    <row>
        <code>TO</code>
        <value>NAMELINE_TO</value>
    </row>
    <row>
        <code>NUMBER</code>
        <value>002</value>
    </row>
    <row>
        <code>TO</code>
        <value>NAMELINE_TO</value>
    </row>
    <row>
        <code>NUMBER</code>
        <value>003</value>
    </row>
    <row>
        <code>FROM</code>
        <value>NAMELINE_FROM</value>
    </row>
    <row>
        <code>NUMBER</code>
        <value>004</value>
    </row>
    <row>
        <code>TO</code>
        <value>NAMELINE</value>
    </row>
    <row>
        <code>FROM</code>
        <value>NAMELINE</value>
    </row>
    <row>
        <code>EXCLUDE</code>
        <value>VALUE1</value>
    </row>
    <row>
        <code>EXCLUDEALSO</code>
        <value>VALUE2</value>
    </row>
</data>

And it needs to be transformed to the following XML:

<?xml version="1.0" encoding="UTF-8"?>
<data>
    <row>
        <code>EXCLUDE</code>
        <value>VALUE1</value>
    </row>
    <row>
        <code>EXCLUDEALSO</code>
        <value>VALUE2</value>
    </row>
    <group>
        <row>
            <code>NUMBER</code>
            <value>001</value>
        </row>
        <row>
            <code>FROM</code>
            <value>NAMELINE_FROM</value>
        </row>
        <row>
            <code>TO</code>
            <value>NAMELINE_TO</value>
        </row>
    </group>
    <group>
        <row>
            <code>NUMBER</code>
            <value>002</value>
        </row>
        <row>
            <code>TO</code>
            <value>NAMELINE_TO</value>
        </row>
    </group>
    <group>
        <row>
            <code>NUMBER</code>
            <value>003</value>
        </row>
        <row>
            <code>FROM</code>
            <value>NAMELINE_FROM</value>
        </row>
    </group>
    <group>
        <row>
            <code>NUMBER</code>
            <value>004</value>
        </row>
        <row>
            <code>TO</code>
            <value>NAMELINE</value>
        </row>
        <row>
            <code>FROM</code>
            <value>NAMELINE</value>
        </row>
    </group>
    <row>
        <code>EXCLUDE</code>
        <value>VALUE1</value>
    </row>
    <row>
        <code>EXCLUDEALSO</code>
        <value>VALUE2</value>
    </row>
</data>

The rules to be applied:

  1. Some rows needs to be excluded from the grouping. These would be the rows that do not have the code NUMBER, FROM or TO.
  2. When code NUMBER appears a new group starts
  3. FROM and TO could be in different order
  4. Rows that have to be exclude will always be in front and/or at the end of the to be grouped codes. It will never appear in between.

In XSLT 2.0 this would be easy and I have the solution, but in XSLT 1.0 I do not know where to start.

1

1 Answers

1
votes

Here is a stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

   <xsl:output indent="yes"/>
   <xsl:strip-space elements="*"/>

   <xsl:key name="group" match="row[code = 'TO' or code = 'FROM']" use="generate-id(preceding-sibling::row[code = 'NUMBER'][1])"/>
   <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="row[code = 'NUMBER']">
      <group>
        <xsl:copy-of select=". | key('group', generate-id())"/>
      </group>
    </xsl:template>

    <xsl:template match="row[code = 'FROM' or code = 'TO']"/>

</xsl:stylesheet>