Contents


Tip

Call JavaScript from an XSLT style sheet

Add functionality to your style sheets

Comments

Content series:

This content is part # of # in the series: Tip

Stay tuned for additional content in this series.

This content is part of the series:Tip

Stay tuned for additional content in this series.

This tip uses the Apache Project's Xalan Java 2 transformation engine and its implementation (see Related topics). 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 Related topics), 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
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
The final output

Downloadable resources


Related topics


Comments

Sign in or register to add and subscribe to comments.

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