A fragment of the results tree before node-set: a general approach for all xsl engines

The answer is to another thread (see https://stackoverflow.com/a/1674747 ). I ran into a problem below where different xsl engines seem to need different approaches when converting fragments of the result tree to node-sets.

To simplify the problem (but see the link above for the full story), I want to have a built-in tree containing a list of color values. Since this should be used in Xpath expressions, I had to create a node-set from it specifically for the MSXML xx xsl engine (the built-in XML spy had less trouble interpreting Xpath expressions associated with variables built as rtf).
Another thread https://stackoverflow.com/a/236329/2123 helped me there. The resulting node -set is used to create a new rtf variable from the input XML.
Again, MSXML complains when a 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 xx no longer causes errors.
But when I run the same in Spy or Saxon 9he inline XML, I get another error: the node-set function seems to be 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 have simplified things; I just want to know how to write an XSLT 1.0 transform that will work on all xsl machines.

Used XSLT:

 <?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 

leads to the built-in xsl engine in XML Spy:

 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' 
+4
source share
5 answers

For processors other than MSXML, use the exslt function: node -set (). (Http://www.exslt.org/). (It’s a little strange to bind the exslt prefix to the version of this Microsoft function - it confused me a little!)

You can check which functions are available with the-available () function:

 <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 do not need any of these functions, so use

 <xsl:when test="xsl:version='2.0'"> 
+5
source

To avoid the need to do

  <xsl:choose> <xsl:when test="function-available('exslt:node-set')"... 

every time you need it, you can define the exslt node for the xslt2 engines (using xsl: function) and for msxml (using msxsl: script), and then just use the exslt: node -set function in the rest of the document.

http://dpcarlisle.blogspot.co.uk/2007/05/exslt-node-set-function.html

shows you how to define it for msxml and for xslt2 engines you can xsl: include a stylesheet

 <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" > <xsl:function name="exslt:node-set"> <xsl:param name="rtf"/> <xsl:sequence select="$rtf"/> </xsl:function> <xsl:stylesheet> 

XSLT1 direct compatibility rules mean it's safe to enable, the XSLT1 engine will simply ignore it.

+3
source

Well Saxon 9 is an XSLT 2.0 processor, and with XSLT 2.0, one of the main improvements is that the distinction between node sets and fragments of the result tree has passed and you don’t need any extension function at all, since you no longer have to force which any coercion. Thus, with style sheets aimed at any XSLT 2.0 processor, you should simply give up any attempt to use such an extension function, then the style sheet will work. If you want to run the same stylesheet with XSLT 1.0 and 2.0 processors, then I see a problem, but I don't think there is a simple solution. You will need to use the http://www.w3.org/TR/xslt#function-function-available and system property to distinguish between processors and the availability of extension functions.

+1
source

Microsoft.NET XsltCompiledTransform XSLT processor supports exslt: node -set ().

For MSXML, you can use your own implementation of a subset of the EXSLT functions - for MSXML. You can find a detailed description and download link here:

http://www.xml.com/pub/a/2003/08/06/exslt.html

+1
source

Well, you can easily do this without any checks. Just follow the diagram described here: http://dpcarlisle.blogspot.co.uk/2007/05/exslt-node-set-function.html

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="exslt msxsl"> <msxsl:script language="JScript" implements-prefix="exslt"> this['node-set'] = function (x) { return x; } </msxsl:script> <xsl:variable name="x"> <y/> </xsl:variable> <xsl:template match="x"> <html> <head><title>test exslt node set</title></head> <body> <xsl:apply-templates select="exslt:node-set($x)/*"/> </body> </html> </xsl:template> <xsl:template match="y"> <p>node set!</p> </xsl:template> </xsl:stylesheet> 

It definitely works in FF, Chrome and IE7 +

-one
source

All Articles