xsl-list
[Top] [All Lists]

[xsl] XML: From flat to hierarchical with grouping

2017-03-28 21:12:15
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
--~----------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
EasyUnsubscribe: http://lists.mulberrytech.com/unsub/xsl-list/1167547
or by email: xsl-list-unsub(_at_)lists(_dot_)mulberrytech(_dot_)com
--~--

<Prev in Thread] Current Thread [Next in Thread>