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 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> |
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.
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
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.
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
- Check out the XSLT recommendation from the W3C.
- Download Apache's Xalan-Java 2.
- Download the js.jar file.
- Find more XML resources on the developerWorks XML zone.
-
IBM trial software: Build your next development project with trial software available for download directly from developerWorks.

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)





