Read XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition Online
Authors: Michael Kay
select=“seconds-from-time(current-time()) mod 1.0e0”
use-when=“not(function-available(‘random:random-sequence’, 2))”
xmlns:random=“http://exslt.org/random”/>
select=“random:random-sequence(1, ())”
use-when=“function-available(‘random:random-sequence’, 2)”
xmlns:random=“http://exslt.org/random”/>
(In fact, the
use-when
attribute on the first
use-when
attribute on the second variable evaluates to true, this variable will shadow the first variable, and it does no harm for both variables to be present.)
Note that the rules for the
use-when
attribute require it to be a condition that can be evaluated at compile time. It's therefore not permitted in this expression to reference the values of variables or stylesheet parameters, or to access the contents of a source document.
You can use similar techniques to make a stylesheet portable between different XSLT versions. In this case there are additional facilities available, notably the
[xsl:]version
attribute, which can be attached to any element in the stylesheet. Version compatibility is fully discussed in Chapter 3, on page 128.
Summary
Extension functions are useful to extend the capabilities of XSLT stylesheets. They allow stylesheets to access external system services and to perform calculations that are difficult or inefficient to achieve in “pure” XSLT and XPath.
There are other extensibility mechanisms in XSLT, including extension instructions, extension declarations, and extension attributes, but extension functions are by far the most widely used, so that's what we concentrated on in this chapter.
In the next chapter, we move away from detailed specifications of interfaces and look at using the facilities of XSLT to create well-designed stylesheets.
Chapter 17
Stylesheet Design Patterns
This chapter looks at four common design patterns for XSLT stylesheets.
The concept of design patterns was introduced by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides in their classic book
Design Patterns: Elements of Reusable Object-Oriented Software
(Addison-Wesley Publishing, 1995). Their idea was that there was a repertoire of techniques that were useful again and again. They presented 23 different design patterns for object-oriented programming, claiming not that this was a complete list but that the vast majority of programs written by experienced designers fell into one or more of these patterns.
For XSLT stylesheets, the vast majority of stylesheets I have seen fall into one of four design patterns. These are as follows:
Again, this doesn't mean that these are the only ways you can write stylesheets, nor does it mean that any stylesheet you write must follow one of these four patterns to the exclusion of the other three. It just means that a great many stylesheets actually written by experienced people follow one of these four patterns, and if you become familiar with these patterns, you will have a good repertoire of techniques that you can apply to solving any given problem.
I describe the first three design patterns rather briefly, because they are not really very difficult. The fourth, the computational design pattern, is explored in much greater depth—not because it is encountered more often, but because it requires a different way of thinking about algorithms than you use with conventional procedural programming languages.
Fill-in-the-Blanks Stylesheets
Many proprietary templating languages have been built up around HTML. The template looks largely like a standard HTML file but with the addition of extra tags used to retrieve variable data and insert it at a particular point in the HTML data page. The designers of XSLT took care to ensure that, in spite of the power of XSLT as a full transformation language, it would still be possible to use it in this simple way, bringing it within the reach of nonprogrammers with HTML authoring skills.
Example: A “Fill-in-the-Blanks” Stylesheet
Here's an example of such a stylesheet. It uses the
simplified stylesheet
syntax, so the
Input
This XML document,
orgchart.xml
, represents an organization chart showing the senior management of a certain company at a particular date. It is organized as a recursive structure that directly reflects the management hierarchy. You may recognize the names, but the roles are entirely fictitious.
Stylesheet
There are many creative ways to display this data; for example, you could use SVG graphics, Explorer-style trees implemented in client-side JavaScript, or just indented lists. I'm not trying to teach you any clever HTML tricks, so in this stylesheet (
orgchart.xsl
) I'll show the data instead, as a rather boring table, with one row per person and three columns for the person's name, their title, and the name of their boss.
xsl:version=“2.0”>
Management Structure
The following responsibilities were announced on
‘[D1] [MNn] [Y1]’)”/>:
Name Role Reporting to
The key to this design pattern is that the stylesheet has the same structure as the desired output. Fixed content is included directly in the stylesheet as text or as literal result elements, while variable content is included by means of
Output
The output of this stylesheet is shown in
Figure 17-1
.
This kind of stylesheet makes very limited use of XSLT's power, but it is very similar to a wide variety of proprietary templating languages currently in use. Experience has shown that this kind of stylesheet is easy for experienced HTML authors to write, even if they have no programming training. This is an important consideration, because on many larger Web sites there is a constant need to introduce new page templates at very short notice, and this becomes much easier to achieve if content authors and editors can do the work themselves.
One restriction, of course, is that the input has to come from an XML document. This contrasts with most of the proprietary languages, where the input often comes directly from a relational database. Fortunately, all popular relational databases now provide convenient ways to extract data from a database in XML form. Ideally, this doesn't even need to be a serial XML document that has to be re-parsed by the XSLT processor. It will often be possible to transfer the data directly from the database to the XSLT processor in a structured form; for example, as a DOM tree in memory or as a SAX event stream. The details of how to do this depend on the database product you are using and are beyond the scope of this book.
Another approach is to use the
document()
function (described in Chapter 13, page 754) with a URI that addresses a servlet with parameters to retrieve the required data.
Navigational Stylesheets
Navigational stylesheets are a natural progression from simple fill-in-the-blanks stylesheets.
Like fill-in-the-blanks stylesheets, a navigational stylesheet is still essentially output-oriented. However, it is now likely to use named templates or stylesheet functions as subroutines to perform commonly needed tasks; it may use variables to calculate values needed in more than one place, and it may use constructs such as keys, parameters, and sorting.
Whereas a fill-in-the-blanks stylesheet looks like HTML sprinkled with a few extra control statements, a navigational stylesheet (once you look beyond the angle-bracket syntax) has a rather similar structure to a conventional procedural program with variables, conditional statements, for loops, and subroutine calls.
Navigational stylesheets are often used to produce reports on data-oriented XML documents, where the structure of the source document is regular and predictable.
Example: A Navigational Stylesheet
This example shows the use of a navigational stylesheet to produce a very simple sales report.
Input
Suppose the source document,
booklist.xml
, looks like this:
Stylesheet
The following navigational stylesheet (
booksales.xsl
) produces a report on the total number of sales for each publisher.
xmlns:xs=“http://www.w3.org/2001/XMLSchema”
exclude-result-prefixes=“xs”
version=“2.0”>
We need to declare a variable that refers to the input document, for later use in a named template that has no context node.
The global variable
$publishers
is a sequence of strings containing one string for each distinct publisher found in the source file. This uses the new
distinct-values()
function introduced in XPath 2.0.
select=“distinct-values(/booklist/book/publisher)”/>
The main template iterates over the distinct publishers using
Sales volume by publisher
Publisher Total Sales Value
Finally, a named template that calculates the total sales for the publisher. The name of the publisher is supplied as an implicit parameter in the context node; however, to make the template more reusable a parameter is declared with this as the default.
This stylesheet is not very far removed from the fill-in-the-blanks example earlier in the chapter. But because it uses some top-level elements such as
Output
The output is shown in
Figure 17-2
.