[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

Re: [xsl] Help to unflatten xml file


Subject: Re: [xsl] Help to unflatten xml file
From: "G. Ken Holman" <gkholman@xxxxxxxxxxxxxxxxxxxx>
Date: Tue, 30 Nov 2010 17:16:06 -0500

At 2010-11-30 15:43 -0600, Steve Ylvisaker wrote:
I want to nest sections from a flat XML file based on the value of a section attribute. I have done this before with a similar but slightly different situation. I'm missing something with the behavior of xsl:for-each-group.

Actually, you missed a very basic first step and were off on a tangent with your testing. Once that first step is made correctly, then it was just a matter of finding out what was missing.


<xsl:template match="/">
<xsl:variable name="unflattenedDoc">
<book>
<xsl:copy>
<xsl:for-each-group select="*" group-starting-with="section[@label=1]">

Note that you are selecting all of the children of the *root* node, not of the document element ... in my example before I'm selecting "*/*".


With that first step made correctly, then the rest falls into place.

I hope the answer below helps.

. . . . . . . . . Ken

p.s. I'm assuming your "pass2" is going to eventually be more detailed than simply preserving the nodes, because if not then you don't need the second pass.

T:\ftemp>type steve.xml
<?xml version="1.0" encoding="UTF-8"?>
<book type="Tech_Manual">
    <bookinfo>
        <title>client manual</title>
        <subtitle>performance data</subtitle>
    </bookinfo>
    <section id="a--21" label="1">
        <title lang="en">Preface</title>
        <para>some interesting stuff</para>
    </section>
    <section id="a--22" label="2">
        <title lang="en">Preface</title>
        <para>some more interesting stuff</para>
    </section>
    <section id="a--23" label="2">
        <title lang="en">Preface</title>
        <para>some more interesting stuff</para>
    </section>
    <section id="a--24" label="3">
        <title lang="en">Preface</title>
        <para>some more interesting stuff</para>
    </section>
    <section id="a--25" label="1">
        <title lang="en">Cautions</title>
        <para>some interesting stuff</para>
    </section>
</book>

T:\ftemp>call xslt2 steve.xml steve.xsl
<?xml version="1.0" encoding="utf-8"?>
<book>
   <bookinfo>
      <title>client manual</title>
      <subtitle>performance data</subtitle>
   </bookinfo>
   <section id="a--21" label="1">
      <title lang="en">Preface</title>
      <para>some interesting stuff</para>
      <section id="a--22" label="2">
         <title lang="en">Preface</title>
         <para>some more interesting stuff</para>
      </section>
      <section id="a--23" label="2">
         <title lang="en">Preface</title>
         <para>some more interesting stuff</para>
         <section id="a--24" label="3">
            <title lang="en">Preface</title>
            <para>some more interesting stuff</para>
         </section>
      </section>
   </section>
   <section id="a--25" label="1">
      <title lang="en">Cautions</title>
      <para>some interesting stuff</para>
   </section>
</book>
T:\ftemp>type steve.xsl
<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs">


<xsl:output method="xml" omit-xml-declaration="no" encoding="utf-8" indent="yes"/> <xsl:strip-space elements="*"/>


<!-- Pass one - recognize section headers and create nested <sections/> -->
<xsl:template match="/">
<xsl:variable name="unflattenedDoc">
<book>
<xsl:copy>
<xsl:for-each-group select="*/*" group-starting-with="section[@label=1]">
<xsl:apply-templates select="." mode="group"/>
</xsl:for-each-group>
</xsl:copy>
</book>
</xsl:variable>
<xsl:apply-templates select="$unflattenedDoc" mode="pass2"/>
</xsl:template>


  <xsl:template match="section[@label=1]" mode="group">
    <section>
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates mode="group"/>
        <xsl:for-each-group select="current-group()[position()>1]"
                            group-starting-with="section[@label=2]">
            <xsl:apply-templates select="." mode="group"/>
        </xsl:for-each-group>
    </section>
  </xsl:template>

  <xsl:template match="section[@label=2]" mode="group">
    <section>
      <xsl:copy-of select="@*"/>
      <xsl:apply-templates mode="group"/>
        <xsl:for-each-group select="current-group()[position()>1]"
                            group-starting-with="section[@label=3]">
            <xsl:apply-templates select="." mode="group"/>
        </xsl:for-each-group>
    </section>
  </xsl:template>

  <xsl:template match="section[@label=3]" mode="group">
     <section>
       <xsl:copy-of select="@*"/>
       <xsl:apply-templates mode="group"/>
     </section>
  </xsl:template>


<xsl:template match="node()" mode="group"> <xsl:copy-of select="."/> </xsl:template>


<!-- 2nd pass --> <xsl:template match="book" mode="pass2"> <xsl:copy-of select="."/> </xsl:template>

</xsl:stylesheet>

T:\ftemp>rem Done!



--
Contact us for world-wide XML consulting & instructor-led training
Crane Softwrights Ltd.          http://www.CraneSoftwrights.com/s/
G. Ken Holman                 mailto:gkholman@xxxxxxxxxxxxxxxxxxxx
Legal business disclaimers:  http://www.CraneSoftwrights.com/legal


Current Thread
Keywords
xml