ThunderFrame
ThunderFrame

Reputation: 9461

Converting flat hierarchy to nested hierarchy in XSLT depth

I have some frustratingly flat XML that looks like this:

<groups>
    <group id="1" depth="1" />
    <group id="2" depth="2" />
    <group id="3" depth="2" />
    <group id="4" depth="3" />
    <group id="5" depth="2" />
    <group id="6" depth="3" />
</groups>

The maximum value of depth appears to be 5.

Which I'd like to turn into XML that looks like this:

<groups>
    <group id="1" depth="1">
        <group id="2" depth="2">
        </group>
        <group id="3" depth="2">
            <group id="4" depth="3">
            </group>
        </group>
        <group id="5" depth="2">
            <group id="6" depth="3">
            </group>
        </group>
    </group>
</groups>

I think I need to use an xsl:key and then for each parentDepth match the following nodes that have depth = parentDepth + 1 until I reach a node with depth <= parentDepth, but I'm unsure how to implement such a rule.

I suppose another logical approach might be to start from the "bottom" and find the most recent node that has depth = childDepth - 1, but I'm unsure if that can even be achieved in XSLT.

I'm also unsure if this can be done recursively for each depth?

I'm using XSLT 1.0.

Upvotes: 1

Views: 627

Answers (1)

michael.hor257k
michael.hor257k

Reputation: 116992

I think I need to use an xsl:key and then for each parentDepth match the following nodes that have depth = parentDepth + 1

No, you need to look at it in the opposite direction: let each child find its parent and learn its unique id, so it can be called by it.

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:key name="child" match="group" use="generate-id(preceding-sibling::group[@depth=current()/@depth - 1][1])" />

<xsl:template match="/groups">
    <xsl:copy>
        <xsl:apply-templates select="group[@depth=1]"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="group">
     <group id="{@id}" depth="{@depth}">
        <xsl:apply-templates select="key('child', generate-id())"/>
    </group>
</xsl:template>

</xsl:stylesheet>

Upvotes: 3

Related Questions