xsl-list
[Top] [All Lists]

Re: How to output open/close tags independently?

2002-12-27 00:56:17

"Mitch Amiano" <mitch(_dot_)amiano(_at_)softwareadjuvant(_dot_)com> wrote in 
message
news:3E0B8F7F(_dot_)6050609(_at_)softwareadjuvant(_dot_)com(_dot_)(_dot_)(_dot_)
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