Re: [xsl] flatened hiearchies for xslt2

Subject: Re: [xsl] flatened hiearchies for xslt2
From: "Dimitre Novatchev" <dnovatchev@xxxxxxxxx>
Date: Wed, 7 Mar 2007 09:41:41 -0800
My question is:
What is the best approach to transform the "flat" structure back to the
original logical structure, with XSLT2 (Saxon), assuming that only the
'flat' version is received by the application?

Something as simple as this transformation (XSLT 1.0):


<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="kChildren" match="section"
   use="generate-id(preceding::section
                         [@level = current()/@level - 1]
                         [last()]
                    )"
 />
	
 <xsl:template match="/">
    <section id="logical">
      <xsl:apply-templates select="*/section[@level = 1]"/>
    </section>
 </xsl:template>
	
	<xsl:template match="section[@level]">
	  <xsl:copy>
	    <xsl:copy-of select="@*"/>
	    <xsl:apply-templates select="key('kChildren', generate-id())"/>
	  </xsl:copy>
	</xsl:template>
</xsl:stylesheet>

When applied on the provided source xml document:

<section id="flat">
	<section id="1" level="1"/>
	<section id="1-1" level="2"/>
	<section id="1-2" level="2"/>
	<section id="1-2-1" level="3"/>
	<section id="1-2-2" level="3"/>
	<section id="2" level="1"/>
</section>

the wanted result is produced:

<section id="logical">
 <section id="1" level="1">
   <section id="1-1" level="2">
     <section id="1-2-1" level="3" />
     <section id="1-2-2" level="3" />
   </section>
   <section id="1-2" level="2" />
 </section>
 <section id="2" level="1" />
</section>

--
Cheers,
Dimitre Novatchev
---------------------------------------
Truly great madness cannot be achieved without significant intelligence.
---------------------------------------
To invent, you need a good imagination and a pile of junk
-------------------------------------
You've achieved success in your field when you don't know whether what
you're doing is work or play


On 3/7/07, ac <ac@xxxxxxxxxxxxx> wrote:
Hi,

I love functional programming, XSLT2, and Saxon.

I recently faced what first seemed like a simple case, yet it got me
scratching my head for a while, before figuring a workaround for the
real-life problem at hand.  Still it seems so simple that there must be
cleaner way ...

If the following recursive logical XML structure
     <section id="logical">
        <section id="1">
            <section id="1-1"/>
            <section id="1-2">
                <section id="1-2-1"/>
                <section id="1-2-2"/>
            </section>
        </section>
        <section id="2">
        </section>
    </section>

can easily be transformed to its flattened equivalent, like:
    <section id="flat">
        <section id="1" level="1"/>
        <section id="1-1" level="2"/>
        <section id="1-2" level="2"/>
        <section id="1-2-1" level="3"/>
        <section id="1-2-2" level="3"/>
        <section id="2" level="1"/>
    </section>
where the @level attribute represents the "indent" or embedding level.

My question is:
What is the best approach to transform the "flat" structure back to the
original logical structure, with XSLT2 (Saxon), assuming that only the
'flat' version is received by the application?

At first, it is easy to sequentially read and rebuild the sections,
- recursing further when @level increments (embedded sections)
- iterating further when @level remains the same (sibling sections)

But the remaining issue is to manage exit from the recursion, as @levels
come back down.
In the example,  from section 1-2-2 to section 2 (level 3 to level 1).

Note that section ids are hierarchical here only for clarity as in
reality they would be anything.

There must be a 'clean' solution to this relatively common/simple
transformation issue.
Any help or guidance would be appreciated.

Thank you
ac

Current Thread