xsl-list
[Top] [All Lists]

Re: [xsl] Help to unflatten xml file

2010-11-30 16:16:23
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[(_at_)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[(_at_)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[(_at_)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[(_at_)label=2]">
            <xsl:apply-templates select="." mode="group"/>
        </xsl:for-each-group>
    </section>
  </xsl:template>

  <xsl:template match="section[(_at_)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[(_at_)label=3]">
            <xsl:apply-templates select="." mode="group"/>
        </xsl:for-each-group>
    </section>
  </xsl:template>

  <xsl:template match="section[(_at_)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(_at_)CraneSoftwrights(_dot_)com
Legal business disclaimers:  http://www.CraneSoftwrights.com/legal


--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--

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