
XSLT, Browsers, and JavaScript
by Bob DuCharme
February 05, 2003
Most XSLT processors offer some way to tell them: "here is the
source document and here is the stylesheet to use when processing it."
For a command-line XSLT processor, the document and stylesheet are
usually two different parameters specified at the command line.
Web browsers, however, usually read a document from a web server
and have no way to separately be told about the stylesheet to
apply. To remedy this, the W3C Recommendation Associating Style Sheets
with XML Documents describes a processing instruction to include
at the beginning of a document to name a stylesheet to apply to that
document. For example, the processing instruction in the following
numbers.xml document tells an application to apply the stylesheet
squareAsHTML.xsl to that document.
<?xml-stylesheet href="squareAsHTML.xsl" type="text/xsl" ?>
<numbers>
<number>2</number>
<number>11</number>
<number>100</number>
<number>-5</number>
</numbers>
This processing instruction must be at the very beginning of a
document, unless there is an XML declaration before it. Below is the
squareAsHTML.xsl stylesheet referenced by the processing instruction
above:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<!-- squareAsHTML.xsl: create an HTML document with a statement
about the square of each "number" element read from the
source tree. -->
<xsl:template match="/"> <!-- Set up web page -->
<html>
<head>
<title>Squares</title>
<style> <!-- Put a little CSS in -->
body { font-family: arial,helvetica; }
h4 { font-size: 14pt }
p { font-size: 10pt}
</style>
</head>
<body>
<h4>Squares</h4>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="number">
<xsl:variable name="value" select="."/>
<p>
<xsl:text>The square of </xsl:text>
<xsl:value-of select="$value"/>
<xsl:text> is </xsl:text>
<xsl:value-of select="$value * $value"/>.</p>
</xsl:template>
</xsl:stylesheet>
(If you're using XSLT to create result documents with processing
instructions in them, see the earlier column XSLT,
Comments and Processing Instructions for information on XSLT's
xsl:processing-instruction instruction.) Using a command-line
XSLT processor such as Saxon or Xalan to apply the squareAsHTML.xsl
stylesheet to the numbers.xml document creates the following HTML
document:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Squares</title><style>
body { font-family: arial,helvetica; }
h4 { font-size: 14pt }
p { font-size: 10pt}
</style></head>
<body>
<h4>Squares</h4>
<p>The square of 2 is 4.</p>
<p>The square of 11 is 121.</p>
<p>The square of 100 is 10000.</p>
<p>The square of -5 is 25.</p>
</body>
</html>
The best thing about specifying a document's stylesheet with this
xml-stylesheet processing instruction is that it lets you use
the document and designated stylesheet with a web browser. With the
numbers.xml document and stylesheet shown above both sitting in the
same directory of your hard disk, you can tell the current versions of
Mozilla and Internet Explorer to open up numbers.xml and you'll see
the result of the transformation. The rendered result should look the
same as if you had opened an HTML file created by a command-line XSLT
processor using the same input and stylesheet files. (The
command-line processor Saxon does let you specify a
command-line switch telling it to look for the stylesheet name in
this processing instruction.)
You could also put the XML document and stylesheet on a web server,
as I did
here. Follow that link, and you should see the result of the
stylesheet being applied to the XML document. After doing so, try a
View Source, and you'll see the untransformed XML document with a
slight change: I renamed the server copy of the stylesheet to squareAsHTML.xml,
even though it's the exact same stylesheet file. As I write this, my
web server's host provider ships XSLT stylesheets with a MIME type of
text/html, so Mozilla treats them as HTML files. (I've suggested that
they send them as text/xml.) When I give the stylesheet an extension
of "xml", their server ships it with a MIME type of text/xml, so
Mozilla knows that it's not HTML and uses its TransforMiiX XSLT
processor to apply the stylesheet to the document and then renders the
result in the browser.
As long as it's going to be rendered in a browser, you may as well
take advantage of other features that modern browsers offer. My XSLT
stylesheet above added a little CSS stylesheet to the rendered HTML to
set the fonts of the output. By including JavaScript code with your
result HTML, you can take advantage of client-side processing to add
interactivity to the web pages that get created by your XSLT
stylesheet.
Outputting HTML with JavaScript
The following stylesheet resembles the previous one, except that
its head element has a script child element along
with the title and style child elements. JavaScript
code in this script element declares a function that displays
a message box showing the square of the number passed to the
function. If you pass it the number 3, the message box will say "the
square is 9."
For each number element read from the input, instead of
figuring out the square of the number, the second template rule adds a
button to the form created by the first template rule. When clicked,
this button calls the function declared in the script
element.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<!-- squareAsHTMLJS1.xml: create an HTML document with JavaScript that
interactively computes the square of each "number" element read from
the source tree. -->
<xsl:template match="/"> <!-- Set up web page -->
<html>
<head>
<title>Squares</title>
<script language="JavaScript1.2">
function showSquare(n) {
alert("the square is " + n*n);
}
</script>
<style> <!-- Put a little CSS in -->
body { font-family: arial,helvetica; }
h4 { font-size: 14pt }
p { font-size: 10pt}
</style>
</head>
<body>
<h4>Squares</h4>
<p>Click a button to see the square of that number.</p>
<form>
<xsl:apply-templates/>
</form>
</body>
</html>
</xsl:template>
<xsl:template match="number">
<p><input type="button" value=" {.} " onClick="showSquare({.})"/></p>
</xsl:template>
</xsl:stylesheet>
Also in Transforming XML
Automating Stylesheet Creation
Appreciating Libxslt
Push, Pull, Next!
Seeking Equality
The Path of Control
To see this stylesheet in action, send your browser to
this variation
on the numbers.xml document from above. Its only difference from
the original numbers.xml file is that it points to this new XSLT
stylesheet. (Don't take my word for it -- do a View Source to see.)
Again, the stylesheet has an extension of "xml" so that it works as
well with Mozilla as it does with IE.
Putting a lot of JavaScript code inside of a script
element in an XSLT template can get messy, so it's often convenient to
store it in a separate file and then reference it with the
script element's src attribute. This final
variation on numbers.xml points to a stylesheet
that does just that; it looks like the stylesheet above, but its
script element has an src attribute that points to a
squareAsHTMLJS2.js file. The showSquare() code is stored in
squareAsHTMLJS2.js instead of being between the
<script></script> tags in the XSLT stylesheet.
Keeping your JavaScript code in a separate file is cleaner, but
putting it between the <script></script> tags gives you
a powerful opportunity: you don't have to hardcode your JavaScript
code in your XSLT stylesheet; you can write XSLT logic to generate
JavaScript code based on dynamic conditions such as values in your
input. Next month, we'll see how this can let you turn nested
a elements in an XHTML source document into one-to-many links
implemented as pop-up menus in the rendered result.