Tip: Call JavaScript from an XSLT style sheet

Add functionality to your style sheets

XSLT style sheets allow you a great deal of freedom in manipulating the data in your original XML document. There are times, however, when you really want to do actual programming, and the XSLT recommendation is designed to allow that through the use of extensions. These extensions take the form of functions and elements and can be written in any language the processor supports. One of your options is to embed JavaScript within the style sheet, either directly or as an external file.

Nicholas Chase (nicholas@nicholaschase.com), President, Chase and Chase, Inc.

Photo of Nicholas ChaseNicholas Chase has been involved in Web site development for companies such as Lucent Technologies, Sun Microsystems, Oracle, and the Tampa Bay Buccaneers. Nick has been a high school physics teacher, a low-level radioactive waste facility manager, an online science fiction magazine editor, a multimedia engineer, and an Oracle instructor. More recently, he was the Chief Technology Officer of Site Dynamics Interactive Communications in Clearwater, Fla., and is the author of three books on Web development, including Java and XML From Scratch (Que) and the upcoming Primer Plus XML Programming (Sams). He loves to hear from readers and can be reached at nicholas@nicholaschase.com.


developerWorks Master author
        level

01 April 2002

Also available in Japanese

This tip uses the Apache Project's Xalan Java 2 transformation engine and its implementation (see Resources). The overall concepts are the same for any implementation, but the XSLT recommendation doesn't mandate any particular implementation method. In addition to Xalan, you will need the js.jar file (see Resources), which contains an implementation of JavaScript, on your CLASSPATH, as well as bsf.jar, which is part of the Xalan distribution.

The source document

The example style sheet documents the entries in a guessing game, where players make three guesses of 1 to 100. The style sheet takes those three guesses and compares them to random numbers. The sample document contains two sets of guesses:

The sample document
<?xml version="1.0"?>
<entries gameID="DWO">
    <entry>
        <player>John</player>
        <guess>3</guess>
        <guess>9</guess>
        <guess>222</guess>
    </entry>
    <entry>
        <player>Mary</player>
        <guess>88</guess>
        <guess>76</guess>
        <guess>5</guess>
    </entry>
</entries>

Create the component

The first step in using an extension element or function is to define the code to be executed. This involves defining a new namespace and a container for the code:

The basic style sheet
<?xml version="1.0"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:lxslt="http://xml.apache.org/xslt"
                xmlns:result="http://www.example.com/results"
                extension-element-prefixes="result"
                version="1.0">

  <lxslt:component prefix="result" elements="rules" functions="getResult">
    <lxslt:script lang="javascript">
        function getResult (thisGuess) {
          var thisResult = parseInt(Math.random()*100);
          if (thisResult == parseInt(thisGuess)) {
             return "Correct!";
          } else {
             return "Wrong! The actual answer was "+thisResult+
                                                 ", not "+thisGuess+".";
          }
        }
    </lxslt:script>
  </lxslt:component>

  <xsl:template match="/">
      <xsl:apply-templates/>
  </xsl:template>
</xsl:stylesheet>

On the surface, this is a typical style sheet, with the addition of two new namespaces. The first, with the prefix lxslt, tells the processor which elements define the new functionality. The second, result, indicates a call to the new functionality. Finally, the extension-element-prefixes attribute lets the processor know which elements should not be transformed as part of the normal flow. (They can still return a value to be output, as we'll see.)

The component itself specifies that all the code within it will be called from the result namespace prefix. It also lets the processor know which functions will be called from extension elements, and which from extension functions. The script element describes the functions themselves.

In this case, we're starting with a function that takes an argument and compares it to a random number from 1 to 100, returning a string that signifies the result.


Extension functions

In an XSLT style sheet, extension functions actually extend XPath so you can use them just as you would a built-in function such as translate() or round().

Calling a function
...
  <xsl:template match="/">
      <xsl:apply-templates/>
  </xsl:template>

  <xsl:template match="entry">
      Guesser: <xsl:value-of select="player"/>
      <xsl:apply-templates select="guess"/>  
  </xsl:template>

  <xsl:template match="guess">
        Guess: <xsl:value-of select="."/> 
          Actual: <xsl:value-of select="result:getResult(string(.))"/>
  </xsl:template>
</xsl:stylesheet>

This example passes the string value of the current node (guess) to the getResult() function. The namespace lets the processor know to trigger the function in the result component.

Figure 1. Preliminary results
Preliminary results

Using an element

Extension elements are a bit more complex than functions. Rather than simply returning a value (although they can), they are intended to execute a particular action at a particular "time" within the processing of the style sheet. Also, rather than taking an arbitrary list of arguments, as an extension function can, the code behind an extension element has two well-defined arguments.

The rules element triggers the processing of the rules() function. This function takes as one of its arguments the rules element itself (elem), allowing you to retrieve the value of any custom attribute it carries.


Using the processor context

Perhaps the most powerful aspect of an extension element is its ability to access the source document itself through the XSL processor context argument.

The processor context
...
  <lxslt:component prefix="result" elements="rules" functions="getResult">
    <lxslt:script lang="javascript">
...
      function rules(ctx, elem) {
       ctxNode = ctx.getContextNode();
          gameID = ctxNode.getFirstChild().getAttribute("gameID");
          return "Contest "+gameID+" is based on "+
                    elem.getAttribute("guessType")+" guesses.";
      }

    </lxslt:script>
  </lxslt:component>
...

The first argument of the rules function is the processor context, in the form of the org.apache.xalan.extensions.XSLProcessorContext object. This allows you to retrieve objects that represent the context node, the overall source tree, the style sheet, and the transformer currently performing the transformation. Accessing the context node is most common. Once returned by the getContextNode() method, this is a typical XML node, with typical DOM operations available.

Figure 2. The final output
The final output

Resources

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into XML on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML
ArticleID=12098
ArticleTitle=Tip: Call JavaScript from an XSLT style sheet
publish-date=04012002