Tuesday 29 May 2007

The EXSLT node-set function

Following on from a thread on xsl-list which turned to the question of support for the useful xx:node-set() extension function in the XSLT engines used by popular browsers.

Using XPath extension functions in a cross-browser environment is greatly simplified if all the XSLT engines use the same extension namespace. This was one of the motivating reasons behind the community initiative to standardise on the EXSLT extension namespaces.

Opera's XSLT engine supports exslt:node-set, Mozilla/Firefox's XSLT engine doesn't in the current release, but does in the "Gran Paradiso" alpha tests for Firefox 3. Internet Explorer (6 and 7) don't support EXSLT, but do support the functionally identical msxsl:node-set function in the usual msxsl extension namespace.

The usual way to handle exslt:node-set and msxsl:node-set in the same document is to use xsl:choose blocks, with tests on function-available('exslt:node-set') but that is often inconvenient if you want to use xx:node-set in the middle of an XPath.

In the above XSL-List thread I casually suggested that an alternative would be to just always use exslt:node-set in the body of the stylesheet and use the msxsl:script extension to define exslt:node-set for IE. That turned out not to be as easy as I thought as node-set isn't a valid function name in either of the supported extension languages in msxsl (JScript or VBScript). However Julian Reschke came up with the construct needed, use associative array syntax so you can use ['node-set'] to define the function. A complete stylesheet using this technique is shown below

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

The same stylesheet is online together with a test file which just consists of a stylesheet reference and an empty element <x/>.

If your browser supports EXSLT (either natively or using the technique above) viewing the test file link should show "node set!". This appears to work in Firefox Gran paradiso, Internet Explorer 7, Opera 9.21. It doesn't work in Firefox 2 (you get an error message about an unsupported extension function). Users of other browsers that support XSLT (Safari?) feel free to report any results in the comments!

Updated 2008-08-06 to move test file to a different server.

Updated 2009-12-17 to move to google code server. The file now reports that Safari 3.2 supports node-set

7 comments:

M. David Peterson said...

Safari is a no go. No support for node-set.

That said, I have learned from past experience that the Safari folks are responsive to requests for functionality. I think its time we start making those requests!

I'm on it ;-)

Anonymous said...

Apple has been asked to add node-set support over two years ago; see http://drakken.dbc.mtview.ca.us/pipermail/xml2rfc/2005-May/002073.html.

Unknown said...

A wonderfuln solution, thanks!

When I invoke the test file with Firefox 2.0.0.4 I get the error message:
Error loading stylesheet: An XSLT stylesheet does not have an XML mimetype:http://www.dcarlisle.demon.co.uk/ns/nss.xsl

I wanted to test if node-set() is available to give a more helpful error message ...

David Carlisle said...

Sorry about that, you get the same if you try the test file for some
other posts as well.
The Demon ISP changed (without any warning that I noticed) the default
mime type setup on that server and now serve .xsl as text/plain which
breaks XSL use completely.
I've been away at a conference all week, and am trying to get it
fixed, otherwise I'll have to move the tests off that server.

dolmen said...

One year later, could you fix it?

Here is some directions on how to specify a mimetype in a .htaccess.

David Carlisle said...

Sorry about that: I complained repeatedly to demon, but I hadn't noticed quite so much time had gone by.

The problem isn't that I don't know how to change mime types in .htaccess, it's that .htaccess is not enabled on that server (which is essentially a "free" hosting bundled with internet access by the ISP). If I pay them money then I get a full virtual hosting environment and could have full control, but as I'm cross with them for changing the default settings I'm not keen to pay for a full server setup from them. I could switch ISP, but when you've had the same internet presence 12 years or so, changing it isn't something to do in a hurry...

Still I should fix the examples to be hosted on a server that I can control.., thanks for the reminder.

custom written essays said...
This comment has been removed by a blog administrator.