Answering another thread (see stackoverflow: generate css color schemes) I bumped into the issue below, where different xsl engines seem to need different approaches in transforming result tree fragments into node-sets.
Simplifying the issue (but see link above for the full story behind this), I wish to have an inline tree containing a list of color values. As this has to be used in Xpath expressions, I had to create a node-set from it specifically for MSXML x.x xsl engine (XML Spy built-in had less trouble interpreting Xpath expressions contaning variables constructed as rtf's).
Yet another thread stackoverflow: automating-exsltnode-set helped me there.
The resulting node-set is used in creating a new variable rtf from the input XML.
Again, MSXML complains when the new variable is used in Xpath expressions, so I used the node-set function to create a node-set from it.
So far so good, and MSXML x.x does not error any more.
But when I run the same in XML Spy built-in or Saxon 9he, I get another error: it seems that the node-set function is unknown:
Cannot find a matching 1-argument function named {urn:schemas-microsoft-com:xslt}node-set() in variable colorList
Note that this two-step approach is not needed in this particular example, but as I said I simplified things; I just wish to know how to write an XSLT 1.0 transformation that will work in all xsl engines.
The XSLT I used:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:std="http://whatever"
xmlns:exslt="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="std exslt">
<xsl:output method="xml" indent="yes"/>
<std:colors>
<color>#0000FF</color>
<color>#FF0000</color>
</std:colors>
<xsl:variable name="colors" select="document('')/*/std:colors"/>
<xsl:variable name="std:colorList">
<xsl:for-each select="//testid">
<xsl:variable name="pos" select="position() mod 2"/>
<xsl:element name="color">
<xsl:attribute name="testid"><xsl:value-of select="."/></xsl:attribute>
<xsl:value-of select="$colors/color[$pos + 1]"/>
</xsl:element>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="colorList" select="exslt:node-set($std:colorList)"/>
<xsl:template match="/">
<output>
<xsl:copy-of select="$colorList/color"/>
</output>
</xsl:template>
</xsl:stylesheet>
Input file:
<?xml version="1.0" standalone="yes"?>
<NewDataSet>
<defects>
<testid>111</testid>
</defects>
<defects>
<testid>999</testid>
</defects>
</NewDataSet>
Result in MSXML 3.0/4.0/6.0:
<?xml version="1.0" encoding="UTF-16"?>
<output>
<color testid="111">#FF0000</color>
<color testid="999">#0000FF</color>
</output>
Result in Saxon9he:
Cannot find a matching 1-argument function named {urn:schemas-microsoft-com:xslt}node-set()
in variable colorList
result in XML Spy built-in xsl engine:
Error in XPath expression
Unknown function - Name and number of arguments do not match any function signature in the static context - 'urn:schemas-microsoft-com:xslt:node-set'
For processors other than MSXML, use the exslt:node-set() function. (http://www.exslt.org/). (It's a little odd to bind the exslt prefix to the Microsoft version of the function - that had me confused for a while!)
You can test which functions are available using function-available():
<xsl:choose>
<xsl:when test="function-available('exslt:node-set')"...
<xsl:when test="function-available('msxsl:node-set')"...
For Saxon-HE and other XSLT 2.0 processors you don't need any of these functions, so use
<xsl:when test="xsl:version='2.0'">