Search code examples
javascriptxsltxslt-1.0exsltnode-set

How can make an XSLT Javascript extension function return a node-set?


Is there a simple way to have an extension function in XSLT 1.0 written in javascript return a node-set?
I could create a new java class for this, but I would rather just put some code in the script itself.
When this can be done in another scripting language supported by all or most XSLT processors (VB script? Groovy? C#?), then that's OK too of course.

I have the following simple script:

<msxsl:script language="JScript" implements-prefix="custom">
    function xml (input) {
        var x = input.split(";");
        return x.toString();
    }
</msxsl:script>

which returns a string, and hence no problem calling the function in Xpath expressions.
What I would like to have, is a node-set result. But when I change my script to

<msxsl:script language="JScript" implements-prefix="custom">
    function xml (input) {
        var x = input.split(";");
        return x;
    }
</msxsl:script>

then calling the function gives an error because the array is not automatically converted to a node-set.

I looked at arrays-with-java-xslt-extensions but that's more in the line of creating a new class for this, which I wish to avoid for now.

So which statements should be added to the script in order to transform the array into a node-set, allowing the function call to be used in Xpath expressions?


Solution

  • Here is an example that should work with MSXML 6 as long as run in a mode allowing script in XSLT to implement extension functions. The stylesheet code is as follows:

    <xsl:stylesheet
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="1.0"
      xmlns:ms="urn:schemas-microsoft-com:xslt"
      xmlns:my="http://example.com/my"
      exclude-result-prefixes="ms my">
    
      <xsl:output method="html" version="5.0"/>
    
      <ms:script language="JScript" implements-prefix="my">
      <![CDATA[
      function tokenize (input) {
        var doc = new ActiveXObject('Msxml2.DOMDocument.6.0');
        var fragment = doc.createDocumentFragment();
        var tokens = input.split(';');
        for (var i = 0, l = tokens.length; i < l; i++)
        {
          var item = doc.createElement('item');
          item.text = tokens[i];
          fragment.appendChild(item);
        }
        return fragment.selectNodes('item');
      }
      ]]>
      </ms:script>
    
      <xsl:template match="/">
        <html>
          <head>
            <title>Example</title>
          </head>
          <body>
            <h1>Example</h1>
            <ul>
              <xsl:apply-templates select="my:tokenize('Kibology;for;all')"/>
            </ul>
          </body>
        </html>
       </xsl:template>
    
       <xsl:template match="item">
         <li>
           <xsl:value-of select="."/>
         </li>
       </xsl:template>
    
    </xsl:stylesheet>