I could try still speeding up the non-recursive algorithm, by
using a faster search than linear to find the position of a
record node in the string with positions -- this will require
that all positions must have the same (some maximum) length.
Or I could record the positions in a node-set, for which
binary search is straight-forward.
In case you are still not satisfied with the speed of the
non-recursive algorithm, just let me know :o)
Well, I'm more than satisfied with it, but if you want to make
it even faster, don't let me stop you :-)
Dimitre,
One change to your algorithm... the xsl:choose inside the record
match is not required because the continuation records are copied
when each header record is selected. Slightly simpler and I don't
think I broke anything (gives me the same result for my test
case anyway). Here is the new version:
Yes, I know...
Below is the next version, which is speeded up 10-30%. The change is that if
you knoe in advance that the maximum of possible immediate continuation
siblings is a number with N digits, then all position numbers in the string
of positions are coded with this fixed length. This allows not to use
delimiters between every two positions and not to search for a substring.
Instead, the position is found using direct addressing.
Here is the stylesheet (and yes, there's no xsl:choose now):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="pFormatPos" select="string('0001')"/>
<xsl:variable name="vNumLength"
select="string-length($pFormatPos)"/>
<xsl:variable name="vTwiceNumLength"
select="2 * $vNumLength"/>
<xsl:variable name="vposArray">
<xsl:for-each select="/*/record">
<xsl:if test="@type = 'normal'">
<xsl:number value="position()" format="{$pFormatPos}"/>
</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[(_at_)type='normal']"/>
</records>
</xsl:template>
<xsl:template match="record">
<xsl:if test="@type='normal'">
<xsl:variable name="vThisAndNext"
select="substring($vposArray,
(position() - 1)*$vNumLength + 1,
$vTwiceNumLength
)"/>
<xsl:variable name="vNumNested"
select="substring($vThisAndNext, $vNumLength + 1)
-
substring($vThisAndNext, 1, $vNumLength)
- 1"/>
<xsl:copy>
<xsl:copy-of select="@* | node()"/>
<xsl:if test="$vNumNested > 0">
<xsl:copy-of select=
"following-sibling::record
[position() <= $vNumNested]"/>
</xsl:if>
</xsl:copy>
</xsl:if>
</xsl:template>
</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