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

Subject: [xsl] Fwd: [BigList Fwd] Re: XML: From flat to hierarchical with grouping
From: "nick public nickpubl@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Wed, 29 Mar 2017 23:51:44 -0000
Hi Patrik,
Thank you very much for your help.
I appreciate your solution of rec2 recursion key. It's a good idea!

For XSLT 2.0, unfortunatelly it's unsupported. Perhaps is for this that

   <xsl:copy>
     <xsl:for-each-group select="*" group-starting-with="rec1">

fails with the error : "xsl:for-each-group cannot be child of xsl:copy"

Could you help me, please, with a solution in XSLT 1.0?


Thanks a lot
Nicola




---------- Messaggio inoltrato ----------
From: nick public <nickpubl@xxxxxxxxx>
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Cc:
Bcc:
Date: Wed, 29 Mar 2017 04:11:57 +0200
Subject: XML: From flat to hierarchical with grouping
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


---------- Messaggio inoltrato ----------
From: "Dr. Patrik Stellmann" <Patrik.Stellmann@xxxxxxxxx>
To: "xsl-list@xxxxxxxxxxxxxxxxxxxxxx" <xsl-list@xxxxxxxxxxxxxxxxxxxxxx>
Cc:
Bcc:
Date: Wed, 29 Mar 2017 04:41:31 +0000
Subject: AW: [xsl] XML: From flat to hierarchical with grouping
Hi Nicola,

you need to process the rec2 elements that you got with key('k2',
generate-id()) recursively instead of just copying them. And since
rec1 does not contain rec2 elements the <xsl:apply-templates
select="rec2" /> has no effect.

So this template should work:
<xsl:template match="rec1">
 <xsl:copy>
   <xsl:copy-of select="./*"/>
   <xsl:apply-templates select="key('k2', generate-id())"/>
 </xsl:copy>
</xsl:template>


And if XSLT 2.0 is an option you could write it like this:
 <xsl:template match="row">
   <xsl:copy>
     <xsl:for-each-group select="*" group-starting-with="rec1">
       <xsl:copy>
         <xsl:copy-of select="*"/>
         <xsl:for-each-group select="current-group()[position() > 1]"
group-starting-with="rec2">
           <xsl:copy>
             <xsl:copy-of select="*"/>
             <xsl:copy-of select="current-group()[position() > 1]"/>
           </xsl:copy>
         </xsl:for-each-group>
       </xsl:copy>
     </xsl:for-each-group>
   </xsl:copy>
 </xsl:template>


Some comments to the other code:
- <xsl:apply-templates select="//root/row" /> will look for any root
element on any level. If you know the root element can only be on top
level you should use select="root/row".
- <xsl:template match="//row"> is identical to <xsl:template match="row">
- <xsl:copy-of select="./*"/> is identical to <xsl:copy-of select="*"/>

Regards,
Patrik


------------------------------------------------------------------
Systemarchitektur & IT-Projekte
Tel: +49 40 33449-1142
Fax: +49 40 33449-1400
E-Mail: mailto:Patrik.Stellmann@xxxxxxxxx

Current Thread