[xsl] Re: Re: Re: Re: Re: Unbounded element grouping/concatenation

Subject: [xsl] Re: Re: Re: Re: Re: Unbounded element grouping/concatenation
From: "Dimitre Novatchev" <dnovatchev@xxxxxxxxx>
Date: Fri, 12 Dec 2003 13:30:09 +0100
"Michael Kay" <mhk@xxxxxxxxx> wrote in message
news:000b01c3c0a4$b7bd9390$6401a8c0@xxxxxxxxxx
> Dimitre, I would be very grateful if you can make the source files and
> stylesheets for this test available.
>
> Many thanks,
>
> Michael Kay

Yes Mike,

Here they are:

source1000.xml:
===========
<records>
   <record n="1" type="normal"/>
   <record n="2" type="normal"/>
   <record n="3" type="continuation"/>
   <record n="4" type="continuation"/>
   <record n="5" type="continuation"/>
   <record n="6" type="continuation"/>
   <record n="7" type="continuation"/>
 <!--..............................................................
  This means "and so on"
.....................................................................
-->
   <record n="1000" type="continuation"/>
   <record n="1001" type="continuation"/>
   <record n="1002" type="continuation"/>
   <record n="1003" type="normal"/>
   <record n="1004" type="normal"/>
</records>

source2000.xml:
===========
<records>
   <record n="1" type="normal"/>
   <record n="2" type="normal"/>
   <record n="3" type="continuation"/>
   <record n="4" type="continuation"/>
   <record n="5" type="continuation"/>
   <record n="6" type="continuation"/>
   <record n="7" type="continuation"/>
 <!--..............................................................
  This means "and so on"
.....................................................................
-->
   <record n="2000" type="continuation"/>
   <record n="2001" type="continuation"/>
   <record n="2002" type="continuation"/>
   <record n="2003" type="normal"/>
   <record n="2004" type="normal"/>
</records>

These can be easily generated with the following XSLT 2.0 stylesheet,
setting the $pnumNodes respectively to 1000 and 2000.

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
  <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:param name="pnumNodes" select="1000"/>

  <xsl:template match="/">
    <records>
      <record n="1" type="normal"/>
      <record n="2" type="normal"/>
      <xsl:for-each select="3 to $pnumNodes + 2">
        <record n="{.}" type="continuation"/>
      </xsl:for-each>
      <record n="{$pnumNodes + 3}" type="normal"/>
      <record n="{$pnumNodes + 4}" type="normal"/>
    </records>
  </xsl:template>
</xsl:stylesheet>


Now the different transformations.

I. Recursive transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*" />

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="records">
    <records>
      <xsl:apply-templates select="record[@type = 'normal']"/>
    </records>
  </xsl:template>

  <xsl:template match="record[@type = 'normal']">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()" />
      <xsl:apply-templates
       select="following-sibling::record[1][@type='continuation']"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="record[@type = 'continuation']">
    <xsl:copy-of select="." />
    <xsl:apply-templates
     select="following-sibling::record[1][@type='continuation']"/>
  </xsl:template>
</xsl:stylesheet>


II. Key-based transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>

  <xsl:key name="kCont" match="record[@type='continuation']"
   use="generate-id(preceding-sibling::record
                           [@type = 'normal'][1]
                    )"/>

  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="records">
    <records>
      <xsl:apply-templates select="record[@type = 'normal']" />
    </records>
  </xsl:template>

  <xsl:template match="record[@type = 'normal']">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()" />
      <xsl:apply-templates
         select="key('kCont', generate-id())"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>


III. Non-recursive transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
 >

  <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:variable name="vposArray">
    <xsl:value-of select="'|'"/>
    <xsl:for-each select="/*/record">
      <xsl:if test="@type = 'normal'">
        <xsl:value-of select="concat(position(), '|')"/>
      </xsl:if>
    </xsl:for-each>
  </xsl:variable>

  <xsl:template match="@* | node()" name="identity">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="records">
    <records>
      <xsl:apply-templates select="record"/>
    </records>
  </xsl:template>

  <xsl:template match="record">
    <xsl:choose>
      <xsl:when test="not(@type='normal')">
        <xsl:call-template name="identity"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:variable name="vPos" select="position()"/>
        <xsl:variable name="vposNext"
        select="substring-before(
                          substring-after($vposArray,
                                          concat('|',
                                                 position(),
                                                 '|'
                                                 )
                                          ),
                          '|'
                                )"/>
         <xsl:variable name="vNumNested"
           select="$vposNext - position() - 1"/>
         <xsl:copy>
           <xsl:copy-of select="@* | node()"/>
           <xsl:if test="$vNumNested > 0">
             <xsl:copy-of select=
               "following-sibling::record
                           [position() &lt;= $vNumNested]"/>
           </xsl:if>
         </xsl:copy>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="record[not(@type='normal')]"/>
</xsl:stylesheet>



=====
Cheers,

Dimitre Novatchev.
http://fxsl.sourceforge.net/ -- the home of FXSL




 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread