Re: [xsl] How to output open/close tags independently?

Subject: Re: [xsl] How to output open/close tags independently?
From: Dimitre Novatchev <dnovatchev@xxxxxxxxx>
Date: Thu, 26 Dec 2002 23:56:17 -0800 (PST)
"Mitch Amiano" <mitch.amiano@xxxxxxxxxxxxxxxxxxxx> wrote in message
news:3E0B8F7F.6050609@xxxxxxxxxxxxxxxxxxxxxxx
> I don't see what the connection is between trying to coerce XSLT into
accepting non-well-formed markup, and grouping.
> As others have pointed out, the FAQ gives a good example of how to
group by a fixed number of elements.  For grins, I took your sample and
modified it slightly:
> <?xml version="1.0"?>
> <batchup>
> <x>0</x>
> <x>1</x>
> <x>2</x>
> <x>3</x>
> <x>4</x>
> <x>5</x>
> <x>6</x>
> <x>7</x>
> <x>8</x>
> <x>9</x>
> <x>0</x>
> <x>1</x>
> <x>2</x>
> 
> ... and so on, for 1000 <x> elements.
> 
> Then I wrote a small stylesheet based on the FAQ method:
> 
> <xsl:variable name="groupsize" select="3"/>
> <xsl:template match="/">
>  <xsl:for-each select="batchup/x[position() mod $groupsize = 1]">
>   <xsl:text>&#xA;</xsl:text>
>   <w>
>      <xsl:copy-of select=".|following-sibling::x[position() &lt;
$groupsize]"/>
>   </w>
>  </xsl:for-each>
> </xsl:template>
> 
> and another based on a recursive call-template:
> 
> <xsl:variable name="groupsize" select="3"/>
> <xsl:template match="/">
>   <xsl:call-template name="batchup">
>      <xsl:with-param name="nodes" select="/batchup/x"/>
>   </xsl:call-template>
> </xsl:template>
> <xsl:template name="batchup">
>   <xsl:param name="nodes"/>
>   <xsl:if test="$nodes">
>   <xsl:text>&#xA;</xsl:text>
>   <w>
>   <xsl:copy-of select="$nodes[position() &lt;= $groupsize]"/>
>   </w>
>   <xsl:call-template name="batchup">
>      <xsl:with-param name="nodes" select="$nodes[position() &gt;
$groupsize]"/>
>   </xsl:call-template>
>   </xsl:if>
> </xsl:template>
> 
> Not surprisingly, the second transform took about 5 times longer to
run (83.34 seconds on w2k/saxon6.5.1/750mhz) than the first one (17.46
seconds) (and Windows complained about my virtual memory usage). Not to
mention that the first transform is a smaller amount of code.
> 
> - Mitch 


Hi Mitch,

My results are *very different*. With your set of 1000 elements

On Saxon 6.5.2 I have:
---------------------
non-resursive:   0.251 sec
recursive:       0.280 sec

It was more than a year ago when Mike Kay explained that Saxon
optimises tail recursion implementing it with iteration. This explains
the result.

On MSXML4 (, which does not optimise tail-recursion) the results are:
----------
non-recursive:   0.005 sec.
recursive:       0.046 sec.

so the recursive variant ran 9 times slower.

However, there's a DVC variant (Divide and Conquer, see for example
http://www.topxml.com/code/default.asp?p=3&id=v20020107050418&ms=60&l=xsl&sw=lang),
which allows recursion to run much faster. With it the results were:


Saxon 6.5.2:
-----------
non-resursive:   0.251 sec
recursive:       0.280 sec
DVC:             0.280 sec


MSXML4:
-------
non-recursive:   0.005 sec.
recursive:       0.046 sec.
DVC:             0.014 sec.


My computer is a 1.7 GHz W2K Pentium with 256MB of memory. This is the
reason for the faster times.

However, the difference in speed cannot explain the very different
ratio of recursive / non-recursive reported by you for Saxon.

Here's the code I used (copied your code and added the DVC one):
----------------------
<xsl:stylesheet version="1.0" 
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
  <xsl:variable name="groupsize" select="3"/>
  <!--  
  <xsl:template match="/">  
    <xsl:call-template name="batchup">     
      <xsl:with-param name="nodes" select="/batchup/x"/>  
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="batchup">  
    <xsl:param name="nodes"/>  
    <xsl:if test="$nodes">  
      <xsl:text>&#xA;</xsl:text>  
      <w>  
        <xsl:copy-of select="$nodes[position() &lt;= $groupsize]"/>  
      </w>  
      <xsl:call-template name="batchup">     
        <xsl:with-param name="nodes" 
                        select="$nodes[position() &gt; $groupsize]"/>  
      </xsl:call-template>  
    </xsl:if>
  </xsl:template>

  <xsl:template match="/">      

    <xsl:for-each 
              select="batchup/x[position() mod $groupsize = 1]">       

      <xsl:text>&#xA;</xsl:text>        
      <w>          
        <xsl:copy-of 
   select=".|following-sibling::x[position() &lt; $groupsize]"/>       

      </w>      
    </xsl:for-each>    

  </xsl:template>
-->
  <xsl:template match="/">  
    <xsl:call-template name="batchup">     
      <xsl:with-param name="nodes" select="/batchup/x"/>  
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="batchup">  
    <xsl:param name="nodes"/>  
    <xsl:if test="$nodes">
      <xsl:choose>
        <xsl:when test="not($nodes[position() = $groupsize + 1])">
          <xsl:text>&#xA;</xsl:text>  
          <w>  
            <xsl:copy-of select="$nodes[position() &lt;=$groupsize]"/> 

          </w> 
        </xsl:when> 
        <xsl:otherwise>
          <xsl:variable name="vHalf" 
           select="floor(ceiling(count($nodes) div $groupsize) div 2) 
                   * $groupsize"/>
          <xsl:call-template name="batchup">     
            <xsl:with-param name="nodes" 
                            select="$nodes[position() &lt;= $vHalf]"/> 

          </xsl:call-template>
          <xsl:call-template name="batchup">     
            <xsl:with-param name="nodes" 
                                select="$nodes[position() > $vHalf]"/> 

          </xsl:call-template>
        </xsl:otherwise>  
      </xsl:choose>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>




=====
Cheers,

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

__________________________________________________
Do you Yahoo!?
Yahoo! Mail Plus - Powerful. Affordable. Sign up now.
http://mailplus.yahoo.com

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


Current Thread