Skip to main content

Tip: Call JavaScript from an XSLT style sheet

Add functionality to your style sheets

Nicholas Chase (nicholas@nicholaschase.com), President, Chase and Chase, Inc.
Photo of Nicholas Chase
Nicholas 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.

Summary:  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.

View more content in this series

Date:  01 Apr 2002
Level:  Introductory
Activity:  9262 views

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

About the author

Photo of Nicholas Chase

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

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

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
author1-email=nicholas@nicholaschase.com
author1-email-cc=dwxed@us.ibm.com

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers