Re: [xsl] nested XML using xslt

Subject: Re: [xsl] nested XML using xslt
From: Martin Honnen <Martin.Honnen@xxxxxx>
Date: Fri, 24 Jul 2009 19:04:03 +0200
kurps s wrote:

Here is the input file:


<list1> <litem>000</litem> <list2> <litem>123 </litem>

<list3>
<litem>ABC</litem>
<litem>666</litem>
</list3>
<!-- now this litem element belongs to list 2-->
<litem> 999 I belong to list 2</litem>
<litem> I belong to list 2</litem>
<list3>
<litem> I belong to the new list 3</litem>
</list3>
<litem> I belong to list 2 again</litem>
<list3>
<litem> another list 3</litem>
<list4>
<litem>222</litem>

</list4>
<!-- I belong to lsit 3 now-->
<litem>333</litem>
</list3>
</list2>
</list1>

Here is my desired output:

<level1>
  <text>000</text>
  <level2>
    <text>
      <para>123</para>
    </text>
    <level3>
      <text>
        <para>ABC</para>
      </text>
    </level3>
    <level3>
      <text>
        <para>666</para>
      </text>
    </level3>
  </level2>
  <level2>
    <text>
      <para>999 I belong to list 2</para>
    </text>
  </level2>
  <level2>
    <text>
      <para>I belong to list 2.</para>
    </text>
    <level3>
      <text>
        <para>I belong to the new list 3list 3.</para>
      </text>
    </level3>
  </level2>
  <level2>
    <text>
      <para>I belong to list 2 again</para>
    </text>
    <level3>
      <text>
        <para>another list 3</para>
      </text>
      <level4 id="S022496B8">

Where does that id come from?


        <text>
          <para>222</para>
        </text>
      </level4>
    </level3>

Isn't one level3 missing here, from <!-- I belong to lsit 3 now--> <litem>333</litem>

  </level2>
</level1>

The idea is that every 'litem' element counts as a 'levelX'.

Here is an attempt to solve that with XSLT 2.0:


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

<xsl:output method="xml" indent="yes"/>

<xsl:function name="mf:group" as="element()*">
<xsl:param name="elements" as="element()*"/>
<xsl:param name="level" as="xs:integer"/>
<xsl:for-each-group select="$elements/*" group-starting-with="litem">
<xsl:element name="level{$level}">
<text>
<para>
<xsl:value-of select="."/>
</para>
</text>
<xsl:sequence select="mf:group(current-group() except ., $level + 1)"/>
</xsl:element>
</xsl:for-each-group>
</xsl:function>


  <xsl:template match="/">
    <xsl:sequence select="mf:group(list1, 1)"/>
  </xsl:template>

</xsl:stylesheet>

Using Saxon 9 it produces the following result:

<level1>
   <text>
      <para>000</para>
   </text>
   <level2>
      <text>
         <para>123 </para>
      </text>
      <level3>
         <text>
            <para>ABC</para>
         </text>
      </level3>
      <level3>
         <text>
            <para>666</para>
         </text>
      </level3>
   </level2>
   <level2>
      <text>
         <para> 999 I belong to list 2</para>
      </text>
   </level2>
   <level2>
      <text>
         <para> I belong to list 2</para>
      </text>
      <level3>
         <text>
            <para> I belong to the new list 3</para>
         </text>
      </level3>
   </level2>
   <level2>
      <text>
         <para> I belong to list 2 again</para>
      </text>
      <level3>
         <text>
            <para> another list 3</para>
         </text>
         <level4>
            <text>
               <para>222</para>
            </text>
         </level4>
      </level3>
      <level3>
         <text>
            <para>333</para>
         </text>
      </level3>
   </level2>
</level1>

It does not generate the id as I don't know where that should come from and it does generate a <text><para>...</para></text> for the 'litem' element child of 'list1' as I did not try to implement different treatment for the first level.

--

	Martin Honnen
	http://msmvps.com/blogs/martin_honnen/

Current Thread