In trying XSLT 2.0 to solve the recently posted problem by Mike
Trotman (see "Sorting subtrees based on their maximum depth.") I came
up with the following solution:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/"
exclude-result-prefixes="f"
<xsl:import href="func-maxDepth.xsl"/>
<xsl:output omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<!-- This transformation must be applied to:
testMaximum3.xml
-->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[folder]">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select="folder">
<xsl:sort select="f:maxDepth(.)" data-type="number"/>
</xsl:apply-templates>
<xsl:apply-templates select="node()[not(self::folder)]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
The stylesheet module
func-maxDepth.xsl:
===============
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:f="http://fxsl.sf.net/"
xmlns:MyMaxDepth="MyMaxDepth"
exclude-result-prefixes="xs f MyMaxDepth"
<xsl:import href="func-map.xsl"/>
<xsl:output omit-xml-declaration="yes"/>
<xsl:variable name="vfunMaxDepth"
select="document('')/*/MyMaxDepth:*[1]"/>
<xsl:function name="f:maxDepth" as="xs:integer">
<xsl:param name="pNode" as="node()"/>
<xsl:value-of select="if (not($pNode/node())) then 0
else
max(f:map($vfunMaxDepth, $pNode/node())) + 1"/>
</xsl:function>
<MyMaxDepth:MyMaxDepth/>
<xsl:template match="MyMaxDepth:*">
<xsl:param name="arg1" as="node()"/>
<xsl:sequence select="f:maxDepth($arg1)"/>
</xsl:template>
</xsl:stylesheet>
The stylesheet module
func-map.xsl:
==========
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/"
exclude-result-prefixes="f"
<xsl:import href="func-apply.xsl"/>
<xsl:function name="f:map" as="item()*">
<xsl:param name="pFun" as="element()"/>
<xsl:param name="pList1" as="item()*"/>
<xsl:sequence select=
"for $this in $pList1 return
f:apply($pFun, $this)"
/>
</xsl:function>
</xsl:stylesheet>
And, finally, the stylesheet module
func-apply.xsl:
==========
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/"
exclude-result-prefixes="f"
<xsl:function name="f:apply">
<xsl:param name="pFunc" as="element()"/>
<xsl:param name="arg1"/>
<xsl:apply-templates select="$pFunc">
<xsl:with-param name="arg1" select="$arg1"/>
</xsl:apply-templates>
</xsl:function>
</xsl:stylesheet>
The problem is that when I run the top-most transformation I get the
following error:
Saxon 8.0 from Saxonica
Java version 1.4.2_04
Stylesheet compilation time: 469 milliseconds
Processing
file:/C:/xml/msxml/XML%20SDK/Samples/Tests/Generic/FP/Fxsl/Exslt-Based/marrowtr.xml
Building tree for
file:/C:/xml/msxml/XML%20SDK/Samples/Tests/Generic/FP/Fxsl/Exslt-Based/marrowtr.xml
using class net.sf.saxon.tinytree.TinyBuilder
Tree built in 0 milliseconds
Tree size: 10 nodes, 0 characters, 8 attributes
Building tree for
file:/C:/xml/msxml/XML%20SDK/Samples/Tests/Generic/FP/Fxsl/XSLT2/func-maxDepth.xsl
using class net.sf.saxon.tinytree.TinyBuilder
Tree built in 16 milliseconds
Tree size: 12 nodes, 0 characters, 15 attributes
Error at value-of on line 21 of
file:/C:/xml/msxml/XML%20SDK/Samples/Tests/Generic/FP/Fxsl/XSLT2/func-maxDepth.xsl:
Failure converting {} to a number
Transformation failed: Run-time errors were reported
The run-time error is explained in the last four lines above.
The source xml document on which the transformation is applied is:
<root>
<folder name="1">
<folder name="2"/>
<folder name="3">
<folder name="4"/>
</folder>
</folder>
<folder name="6">
<folder name="7">
<folder name="8">
<folder name="9"/>
</folder>
</folder>
</folder>
</root>
However, I am able to run simpler transforms calling the function
f:maxDepth() for every "folder" element of the above xml document,
e.g. running this transformation:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:f="http://fxsl.sf.net/"
exclude-result-prefixes="f"
<xsl:import href="func-maxDepth.xsl"/>
<xsl:output omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<!-- This transformation must be applied to:
testMaximum3.xml
-->
<xsl:template match="/">
<xsl:value-of select="f:maxDepth(/*/folder[(_at_)name=6])"/>
</xsl:template>
</xsl:stylesheet>
produces the correct result "3" and no error is reported.
The only difference b/n the two transforms is that in the first,
problematic one, I am using f:maxDepth within the @select expression
of xsl:sort.
So, my question is if I'm doing something wrong in the top-most (first
in this message) transformation, or is this a bug in Saxon 8 and if
this is a bug, what is the recommended workaround.
Thanks to Mike Kay in advance,
Cheers,
Dimitre Novatchev.