Re: [xsl] XML: From flat to hierarchical with grouping

Subject: Re: [xsl] XML: From flat to hierarchical with grouping
From: "Michael Kay mike@xxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Wed, 29 Mar 2017 13:32:19 -0000
You can adapt the code at

http://stackoverflow.com/questions/42932880/

which gives a general approach to converting a flat sequence with level
numbers into a nested hierarchy.

This approach handles an arbitrary number of levels; if you only have a
maximum of three then you could possibly simplify it a little.

Michael Kay
Saxonica


> On 29 Mar 2017, at 03:12, nick public nickpubl@xxxxxxxxx
<xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
>
> I need to manipolate this XML:
>
> <root>
>  <row>
>    <rec1>
>      <fld1-1/>
>    </rec1>
>    <rec2>
>      <fld2-1/>
>    </rec2>
>    <rec3>
>      <fld3-1/>
>    </rec3>
>    <rec3>
>      <fld3-2/>
>    </rec3>
>    <rec2>
>      <fld2-2/>
>    </rec2>
>    <rec3>
>      <fld3-3/>
>    </rec3>
>    <rec3>
>      <fld3-4/>
>    </rec3>
>  </row>
>  <row>
>    <rec1>
>      <fld1-2/>
>    </rec1>
>    <rec2>
>      <fld2-3/>
>    </rec2>
>    <rec3>
>      <fld3-5/>
>    </rec3>
>    <rec3>
>      <fld3-6/>
>    </rec3>
>    <rec2>
>      <fld2-4/>
>    </rec2>
>    <rec3>
>      <fld3-7/>
>    </rec3>
>    <rec3>
>      <fld3-8/>
>    </rec3>
>  </row>
> </root>
>
> to convert it in this other hierarchical structure
> <root_new>
>   <row>
>      <rec1>
>         <fld1-1/>
>         <rec2>
>            <fld2-1/>
>            <rec3>
>               <fld3-1/>
>            </rec3>
>            <rec3>
>               <fld3-2/>
>            </rec3>
>         </rec2>
>         <rec2>
>            <fld2-2/>
>            <rec3>
>               <fld3-3/>
>            </rec3>
>            <rec3>
>               <fld3-4/>
>            </rec3>
>         </rec2>
>      </rec1>
>   </row>
>   <row>
>      <rec1>
>         <fld1-2/>
>         <rec2>
>            <fld2-3/>
>            <rec3>
>               <fld3-5/>
>            </rec3>
>            <rec3>
>               <fld3-6/>
>            </rec3>
>         </rec2>
>         <rec2>
>            <fld2-4/>
>            <rec3>
>               <fld3-7/>
>            </rec3>
>            <rec3>
>               <fld3-8/>
>            </rec3>
>         </rec2>
>      </rec1>
>   </row>
> </root_new>
>
> To better explain, for each <row> element I have to include in <rec1>,
> just 1 per <row>, all <rec2> in same <row> and in each <rec2> all
> following <rec3> until next <rec2> in same <row>.
>
> row-rec1-rec2-rec3-rec3-rec2-rec3
>
> have to e transformed in
> row
>  rec1
>     rec2
>        rec3
>        rec3
>     rec2
>        rec3
>
> <rec1>, <rec2> and <rec3> have own fields <fld*>.
>
> With following script
>
> <?xml version="1.0" encoding="utf-8"?>
> <xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
>    xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl"
>>
>  <xsl:output method="xml" indent="yes"/>
>  <xsl:key name="k2" match="rec2"
> use="generate-id(preceding-sibling::rec1[1])" />
>  <xsl:key name="k3" match="rec3"
> use="generate-id(preceding-sibling::rec2[1])" />
>
>  <xsl:template match="/">
>    <root_new>
>      <xsl:apply-templates select="//root/row" />
>    </root_new>
>  </xsl:template>
>
>  <xsl:template match="//row">
>    <xsl:copy>
>      <xsl:apply-templates select="rec1" />
>    </xsl:copy>
>  </xsl:template>
>
>  <xsl:template match="rec1">
>    <xsl:copy>
>      <xsl:copy-of select="./*"/>
>      <xsl:copy-of select="key('k2', generate-id())"/>
>      <xsl:apply-templates select="rec2" />
>    </xsl:copy>
>  </xsl:template>
>
>  <xsl:template match="rec2">
>    <xsl:copy>
>      <xsl:copy-of select="./*"/>
>      <xsl:copy-of select="key('k3', generate-id())"/>
>    </xsl:copy>
>  </xsl:template>
>
> </xsl:stylesheet>
>
> I can obtain this partial result
>
> <?xml version="1.0" encoding="utf-8"?>
> <root_new>
>  <row>
>    <rec1>
>      <fld1-1 />
>      <rec2>
>        <fld2-1 />
>      </rec2>
>      <rec2>
>        <fld2-2 />
>      </rec2>
>    </rec1>
>  </row>
>  <row>
>    <rec1>
>      <fld1-2 />
>      <rec2>
>        <fld2-3 />
>      </rec2>
>      <rec2>
>        <fld2-4 />
>      </rec2>
>    </rec1>
>  </row>
> </root_new>
>
> but I'm not able to include the <rec3> elements under the <rec2> that
> precede them.
>
> Could you help me please?
>
> Ciao from Italy
> Nicola
>
>
>
>
>
> --------------------------------------------------------
>
> Do you need to index your XML? Try the OpenSource XMLSmartHelper Framework

Current Thread