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

Subject: AW: [xsl] XML: From flat to hierarchical with grouping
From: "Dr. Patrik Stellmann patrik.stellmann@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Wed, 29 Mar 2017 04:41:46 -0000
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

-----UrsprC<ngliche Nachricht-----
Von: nick public nickpubl@xxxxxxxxx
[mailto:xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx]
Gesendet: Mittwoch, 29. MC$rz 2017 04:13
An: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Betreff: [xsl] 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


GDV Dienstleistungs-GmbH
GlockengieCerwall 1
D-20095 Hamburg
www.gdv-dl.de

Sitz und Registergericht: Hamburg
HRB 145291
USt.-IdNr : DE 205183123

GeschC$ftsfC<hrer:
Dr. Jens Bartenwerfer
Michael Bathke
Fred di Giuseppe Chiachiarella
Thomas Fischer

Aufsichtsratsvorsitzender: Werner Schmidt

------------------------------------------------------------------
Diese E-Mail und alle AnhC$nge enthalten vertrauliche und/oder rechtlich
geschC<tzte Informationen. Wenn Sie nicht der richtige Adressat sind oder
diese E-Mail irrtC<mlich erhalten haben, informieren Sie bitte sofort den
Absender und vernichten Sie diese E-Mail. Das unerlaubte Kopieren sowie die
unbefugte Weitergabe der E-Mail ist nicht gestattet.

This e-mail and any attached files may contain confidential and/or privileged
information. If you are not the intended recipient (or have received this
e-mail in error) please notify the sender immediately and destroy this e-mail.
Any unauthorised copying, disclosure or distribution of the material in this
e-mail is strictly forbidden.

Current Thread