"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>
</xsl:text>
<w>
<xsl:copy-of select=".|following-sibling::x[position() <
$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>
</xsl:text>
<w>
<xsl:copy-of select="$nodes[position() <= $groupsize]"/>
</w>
<xsl:call-template name="batchup">
<xsl:with-param name="nodes" select="$nodes[position() >
$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>
</xsl:text>
<w>
<xsl:copy-of select="$nodes[position() <= $groupsize]"/>
</w>
<xsl:call-template name="batchup">
<xsl:with-param name="nodes"
select="$nodes[position() > $groupsize]"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="/">
<xsl:for-each
select="batchup/x[position() mod $groupsize = 1]">
<xsl:text>
</xsl:text>
<w>
<xsl:copy-of
select=".|following-sibling::x[position() < $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>
</xsl:text>
<w>
<xsl:copy-of select="$nodes[position() <=$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() <= $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