XSLT's Template Dispatch
by Clark C. Evans
December 1, 2000
XSLT is a language for transforming XML texts. The language
includes familiar constructs such as for-each iteration,
conditional statements, and callable functions. XSLT also
includes an additional control structure, the template dispatch,
which occurs through the interaction of apply-template/select and
template/match.
This paper presents two templates, one of which uses the template
dispatch, and a second, functionally equivalent to the first,
which is constructed without the help of this control structure.
This paper then concludes with a comparison which may help to
elucidate the power and elegance of XSLT's template dispatch.
Consider the XML input
The C Programming Language
Brian W. Kernighan
Dennis M. Richie
Compilers: Principles, Techniques, and Tools
Alfred V. Aho
Ravi Sethi
Jeffrey D. Ullman
processed by the XSLT stylesheet
Author:
Book:
to produce the following output:
Book: The C Programming Language
Author: Brian W. Kernighan
Author: Dennis M. Richie
Book: Compilers: Principles, Techniques, and Tools
Author: Alfred V. Aho
Author: Ravi Sethi
Author: Jeffrey D. Ullman
Given any input text, the following stylesheet will produce
exactly the same output as the stylesheet above, only it will do
so without the aid of apply-template/select and
apply-template/match. As a consequence, much of its code
necessarily emulates functionality required by the XSLT
specification and built into a compliant XSLT processor.
Author:
Book:
The entry point for a procedural stylesheet is marked by
, a special case similar to a "C" style
main() function. When this template is executed, the current node
for the process is initialized to root node, and then the body,
, transfers control to the
template named dispatch.
The dispatch template begins by creating a variable, $id, which
is used to hold an unique string identifier generated by the XSLT
processor for the current node. Following is a conditional switch
statement having three when clauses and a single otherwise. For
each when clause, a path expression is evaluated and converted
into a boolean value. If true, then the corresponding body is
executed and control resumes immediately after the choose
construct ends. If all of the when clauses fail to fire, then the
body of the otherwise is executed.
The first case, , has a
path expression returning the node-set consisting of any author
element having an identifier equal to the current node's
identifier. Therefore, if the current node happens to be an
author, the node-set returned will be non-empty, which converts
to a true boolean value. This body is executed with two
operations: the non-empty text node "\n Author: " is printed and
then control is transferred to the apply template as specified by
.
The second case, , is
very similar. Only here, the apply template is called with a
parameter named select. The select parameter is the node-set
containing all element children of the current node with a name
of either title or author.
The third case, , only fires
when the current node is a text node. Here
instructs the processor to print the text value of the current
node. Finally, in default, the apply template is called when
none of the previous when clauses have executed.
The last template in the procedural stylesheet, apply, has an
optional parameter select, which is passed as a node-set. If this
parameter is missing, then every child of the current node is
selected. The remainder of this function then iterates through
the selected node-set, calling the dispatch template.
A comparison of the two stylesheets reveals that the first when
clause described above corresponds directly to the first template
of the original stylesheet. In a similar manner, the second when
clause corresponds to the second template of the original
stylesheet. The third when and the default otherwise clause are
needed to emulate the built-in-rule required by the XSLT
specification. A fully compliant emulation would also order the
tests according to XSLT's priority rules.
As you can see with this emulation, a good amount of code is
built into the XSLT processor. Specifically, functionality
similar to the apply template, a default entry point, and a
mechanism similar to the dispatch template are included.
Furthermore, the complexity of this dispatch mechanism increases
when the import statement and mode attribute are considered. The
administration of these and other details is handled by the XSLT
processor, allowing succinct stylesheets like the first one
presented.
Examination of this procedural stylesheet also clarifies the
complementary roles played by select and match expressions. The
select expression chooses which nodes to visit, and, for each
node, the match expressions designate which template to execute.
This allows an ordered set to be selected as a whole, yet each
node in the set to be treated individually. This decoupling of
roles is elegantly managed by the XSLT processor and invoked by
apply-template/select and template/match.
The decoupling of select and match also allows a processor to
pre-compute the match expressions up-front. For example, given an
in-memory node-based implementation, an additional pointer could
be added to each node. After the tree is loaded and before
processing commences, the processor could visit each node in the
tree, filling in a pointer to the template which best matches the
node according to the priority rules. Then, while iterating
through a selected node-set, the template to dispatch is
immediately available without further computation.
XSLT's template mechanism may not be the best solution to every
transformation requirement; however, when the inputs have varying
structure such that relative order among nodes with different
matching criteria is important, its template dispatch approach is
a clear winner.