This solution uses no recursion and hi-lights a few useful XSLT techniques such as Muenchian grouping, keys, finding maximum and iterating without recursion.
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kSectsByValue" match="SectionName"
use="."/>
<xsl:key name="kDocBySect" match="Document"
use="../SectionName"/>
<xsl:variable name="vCols" select=
"/*/*/SectionName
[generate-id()
=
generate-id(key('kSectsByValue',.)[1])
]"/>
<xsl:variable name="vMaxRows">
<xsl:for-each select="$vCols">
<xsl:sort data-type="number" order="descending"
select="count(key('kDocBySect', .))" />
<xsl:if test="position() = 1">
<xsl:value-of select="count(key('kDocBySect', .))"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:template match="/">
<table>
<tr>
<xsl:apply-templates select="$vCols"/>
</tr>
<xsl:for-each select=
"(/*/*/Document)[not(position() > $vMaxRows)]">
<tr>
<xsl:variable name="vPos" select="position()"/>
<xsl:for-each select="$vCols">
<td>
<xsl:value-of select=
"../Document[$vPos]/FileName"/>
</td>
</xsl:for-each>
</tr>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template match="SectionName">
<td>
<xsl:value-of select="." />
</td>
</xsl:template>
</xsl:stylesheet>
when applied on the original XML document (corrected to be well-formed):
<Documents>
<Section>
<SectionName>Green</SectionName>
<Document>
<FileName>Tier 1 Schedules</FileName>
</Document>
<Document>
<FileName>Tier 3 Schedules</FileName>
</Document>
<Document>
<FileName>Setback Schedule</FileName>
</Document>
<Document>
<FileName>Tier 2 Governance</FileName>
</Document>
</Section>
<Section>
<SectionName>MRO/Refurb</SectionName>
<Document>
<FileName>Tier 2 Governance</FileName>
</Document>
</Section>
</Documents>
produces the desired result:
<table>
<tr>
<td>Green</td>
<td>MRO/Refurb</td>
</tr>
<tr>
<td>Tier 1 Schedules</td>
<td>Tier 2 Governance</td>
</tr>
<tr>
<td>Tier 3 Schedules</td>
<td/>
</tr>
<tr>
<td>Setback Schedule</td>
<td/>
</tr>
<tr>
<td>Tier 2 Governance</td>
<td/>
</tr>
</table>
Do note:
We use the Muenchian method for grouping in order to find all different column names, not relying that in the XML document they will be unique.
Keys are used both for the Muenchian grouping and for finding all items belonging to a column.
The maximum number of rows is found and kept in the variable $vMaxRows
We iterate N times to produce the N rows of the table -- not using recursion!
The N
-th row is output by applying templates to all column items that have position N
in their column.