XSLT transforming a flat collection into a hierarchy

Initial payload

This scenario could be used in case we need to append more nodes at the end of the xml doccument. Sample input :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
<?xml version="1.0" encoding="utf-8" ?>
<root>
  <row>
    <id>1</id>
    <parentid></parentid>
    <name>L1-A</name>
    <type>A</type>
  </row>
  <row>
    <id>11</id>
    <parentid>1</parentid>
    <name>L2-AA</name>
    <type>B</type>
  </row>
  <row>
    <id>21</id>
    <parentid>1</parentid>
    <name>L2-AB</name>
    <type>C</type>
  </row>
  <row>
    <id>31</id>
    <parentid>1</parentid>
    <name>L2-AC</name>
    <type>B</type>
  </row>
  <row>
    <id>41</id>
    <parentid>21</parentid>
    <name>L3-ABA</name>
    <type>X</type>
  </row>
  <row>
    <id>51</id>
    <parentid>41</parentid>
    <name>L4-ABAXXX</name>
    <type>D</type>
  </row>
  <row>
    <id>61</id>
    <parentid>31</parentid>
    <name>L2-ACA</name>
    <type>C</type>
  </row>
  <row>
    <id>71</id>
    <parentid>31</parentid>
    <name>L2-ACB</name>
    <type>E</type>
  </row>
  <row>
    <id>2</id>
    <parentid>9</parentid>
    <name>L1-A</name>
    <type>T</type>
  </row>
  <row>
    <id>12</id>
    <parentid>2</parentid>
    <name>L2-AH</name>
    <type>S</type>
  </row>
  <row>
    <id>32</id>
    <parentid>2</parentid>
    <name>L2-AS</name>
    <type>W</type>
  </row>
    <row>
    <id>3</id>
    <parentid>6</parentid>
    <name>L1-R</name>
    <type>T</type>
  </row>
  <row>
    <id>13</id>
    <parentid>3</parentid>
    <name>L2-RH</name>
    <type>S</type>
  </row>
  <row>
    <id>33</id>
    <parentid>3</parentid>
    <name>L2-RWS</name>
    <type>W</type>
  </row>
</root>

Stylesheet

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	exclude-result-prefixes="#all"
	version="3.0">

  <xsl:output method="xml" indent="yes"/>
	
  <!-- generate a key for eachnode -->
  <xsl:key name="childNode" match="/root/row" use="parentid"/>
  
  <!-- selects the root nodes from hierarchies-->
  <xsl:template match="/root">
    <hierarchies>
      <xsl:apply-templates select="/root/row[name='L1-A']"/>
    </hierarchies>
  </xsl:template> 
 
 <!--  apply templates for root nodes-->
  <xsl:template match="/root/row[name='L1-A']">
    <hierarchy>
      <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
        <child>
          <xsl:apply-templates select="key('childNode',./id)"/>
        </child>
      </xsl:copy>
    </hierarchy>
  </xsl:template>

 <!--  apply templates for child nodes-->
 <xsl:template match="root/row">
      <xsl:copy>
          <xsl:apply-templates select="node()|@*"/>
        <child>
        <xsl:apply-templates select="key('childNode',./id)"/>
        </child>
      </xsl:copy>
</xsl:template>

<!-- copy content -->
<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

Result

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
<?xml version="1.0" encoding="UTF-8"?>
<hierarchies>
   <row>
      <id>1</id>
      <parentid/>
      <name>L1-A</name>
      <type>A</type>
      <child>
         <row>
            <id>11</id>
            <parentid>1</parentid>
            <name>L2-AA</name>
            <type>B</type>
            <child/>
         </row>
         <row>
            <id>21</id>
            <parentid>1</parentid>
            <name>L2-AB</name>
            <type>C</type>
            <child>
               <row>
                  <id>41</id>
                  <parentid>21</parentid>
                  <name>L3-ABA</name>
                  <type>X</type>
                  <child>
                     <row>
                        <id>51</id>
                        <parentid>41</parentid>
                        <name>L4-ABAXXX</name>
                        <type>D</type>
                        <child/>
                     </row>
                  </child>
               </row>
            </child>
         </row>
         <row>
            <id>31</id>
            <parentid>1</parentid>
            <name>L2-AC</name>
            <type>B</type>
            <child>
               <row>
                  <id>61</id>
                  <parentid>31</parentid>
                  <name>L2-ACA</name>
                  <type>C</type>
                  <child/>
               </row>
               <row>
                  <id>71</id>
                  <parentid>31</parentid>
                  <name>L2-ACB</name>
                  <type>E</type>
                  <child/>
               </row>
            </child>
         </row>
      </child>
   </row>
   <row>
      <id>2</id>
      <parentid>9</parentid>
      <name>L1-A</name>
      <type>T</type>
      <child>
         <row>
            <id>12</id>
            <parentid>2</parentid>
            <name>L2-AH</name>
            <type>S</type>
            <child/>
         </row>
         <row>
            <id>32</id>
            <parentid>2</parentid>
            <name>L2-AS</name>
            <type>W</type>
            <child/>
         </row>
      </child>
   </row>
</hierarchies>