A template to transform a tree node has the following form:
<xsl:template match="pattern expr"> value replacing the matching node(s) </xsl:template>
Like with XML Schemas, we must distinguish between the XSLT predefined elements
and the elements used to create the document. The namespace xsl
is
most often used for XSLT elements. In order to trigger a
xsl:template
(a production rule), the transformation process must
first identify the node (or nodes) to which it applies. This is done with the
value of the match
attribute that specifies an pattern
expression, a somewhat restricted type of XPath expression.
The content of the xsl:template
defines the structure of the produced tree
by combining any part of the matched tree, new parts or even other parts of the
source document tree. The parts of the tree used as building blocks are referenced by
XPath expressions and combined with functions, conditions, restricted looping
constructs, etc. But the reader must remember that XSLT is a declarative
language (similar to Prolog in some ways), so the ordering of templates cannot be
reliably used to influence the order of processing of the document tree.
A stylesheet follows a simple process: find a node for which a template applies
and then, according to the content of the template, build a new tree structure
in the context of this node. A context gives access to the current node,
its parent, its siblings and its position within its siblings. To build the new
tree structure, a template usually involves the application of templates to
children of the current node and their combination. This is done with the
xsl:apply-templates
element; without attributes, this forces the
application of templates to all the children element nodes of the current node, but
the transformation
can be applied to other nodes by using the select
attribute which
specifies an XPath expression.
Templates can also be named and called with
xsl:call-template
,
similar to procedures in standard programming languages. But be aware that these
procedures are rules and that they cannot have variables that can change
their value. XSLT is thus a single assignment language much like functional
languages; parameters are the only mean of passing variable information between
templates. Contrarily to ordinary templates, named templates do not change the
context of their application. Therefore, we see that the principles underlying
XSLT are general, simple and powerful.
Table 5.1 shows the main stylesheet elements for defining
transformation rules. As a stylesheet is itself an XML document, it can be
validated with the appropriate schema. The root element is
xsl:stylesheet
, which contains a certain number of templates.
xsl:template
with a match
attribute will be called when an element
matching its pattern is encountered during the processing of the XML instance
document. A xsl:template
element with a name
attribute must be
called explicitly by a xsl:call-template
. The content of the matched element
in the source document is replaced with the content of the template, which usually involves
the application of templates to the children of the current node. Formal parameters are declared at the start of an
xsl:template
element with xsl:param
elements.
A xsl:function
element with a name
attribute and xsl:param
elements
can be used to define an XPath function. User-defined function must be declared in a
separate namespace in order to differentiate them from the predefined system functions. Even
though, user-defined function formal parameters are declared with a xsl:param
elements, the actual parameters are given within parenthesis in the order of the declaration
of the xsl:param
elements. Of course, the name of the user-defined function
call must be preceded by the namespace prefix corresponding to the namespace used in the
declaration.
xsl:apply-templates
is the fundamental operation for traversing the document tree. Without
attributes, it indicates that processing should be recursively applied to all its children
elements and text nodes (not to its attributes). If the element is empty, then the nodes are
processed in the document order but it is possible to specify a different ordering with a
xsl:sort
element. Actual parameters can also be given by name and value
using with-param
elements.
xsl:value-of
is the fundamental way of getting the string value contained in an element from
the source document. xsl:copy-of
should be used to get the whole tree value.
A local single assignment variable can be defined within templates
with an xsl:variable
element.
Its string value can then be recovered in an
XPath expression by prefixing its name with $
. If the whole tree value is needed
we can use xsl:copy
to get a reference to the original value and
xsl:copy-of
to get a new copy.
Conditional processing can be achieved with
xsl:if
which
returns its content when the value of its test
attribute is
true
or a non-empty set of nodes.
Also xsl:choose
can
select the first value from a series of alternatives indicated by
xsl:when
. The xsl:when
conditions are tested in sequence and the
first one that returns true
is the value of this element. If no
test succeeds and an xsl:otherwise
element is present, its value
is the value of the xsl:choose
element.
Although recursive traversal of the document tree is the preferred way of
going through nodes, it is also possible to do this traversal iteratively with a
xsl:for-each
and
xsl:for-each-group
.
These templates are especially convenient for transforming a sequence of children nodes
at all the same levels, for example to create tables or summary information.
Node processing is usually conducted in document order but the order can be
changed using xsl:sort
, which allows to specify the sorting key
with the select
attribute and an ascending or descending sort
according to the value of order
attribute. The elements are
usually sorted by their text value but their string value can also be used when sorting by
specifying a data-type
attribute.
In the XPath 1.0, the expression language was quite limited so all control
structures (function definition and calls, alternative or loop constructs) for the
computation of values were the ones of XSLT. But as we have seen in the previous
chapter, with XPath 2.0 we now have the choice between xsl:if
,
xsl:choose
and xsl:for-each
and the if () then ...
else
and for
constructs of XPath. User-defined functions of
XPath 2.0 or XSLT named templates can also be sometimes used interchangeably.
In most cases, this choice is a matter of personal choice but if the function has to be
used in other XPath expressions then it should be written as a function and not as a
named template. Within an XPath function, then the if
and
for
XPath 2.0 must be used. If the function or expression takes atomic
values (string or a number) as input and returns an atomic value, then using an
XPath 2.0 expression or function is more convenient than using a template. Named
templates are most useful for cases when there are default values, when named parameters are
useful or when the current context is needed. In the latter case, the current node would
have to passed as parameter to an XPath function because an XPath function
does not execute in a given context. In practice with XSLT 2.0, templates are almost
exclusively used for producing results that will appear in the output document. Functions
and expressions are more convenient when their result is used by other parts of the
program.
Although XPath
expressions can be used to reference any node or sequence of nodes in an XML file, it is
often convenient and much more efficient to have a direct access to any node in a document.
The xsl:key
element is a top-level declaration indicating to the XSLT
processor that a direct access is needed for nodes matching a given pattern. This
declaration usually implies the building of an index or hash table that allows a
direct matching between a key and a set of nodes matching it. A single key can refer to a
many nodes and a single node can be referred by many keys. Access to the nodes is achieved
with the XPath key
function to which the key value is given. As there can be
many key declarations in a program, the key function must also be given in which index the
search is to be made.
The dynamic creation of target document elements, attributes and text nodes is
performed using the xsl:element
, xsl:attribute
and
xsl:text
elements.
xsl:attribute-set
is useful for grouping many attributes under a single
name and to combine them.
xsl:message
is a very convenient tracing device which writes its content either
on the standard output or another device. It has no effect on the resulting value.
We will now look at examples of these principles and XSL elements in the following sections. First with straightforward transformations into HTML, then into plain text and finally into formatting objects to produce more complex formatting.
Table 5.1. XSLT syntax reminder
<xsl:stylesheet> xsl:import*, (declaration|xsl:variable|xsl:param)* </xsl:stylesheet> |
<xsl:template match="pattern" name="QName"> xsl:param*, sequence-constructor* </xsl:template> |
<xsl:param name="QName" select="expression"> sequence-constructor </xsl:param> |
<xsl:apply-templates select="expression"> (xsl:sort*|xsl:with-param)* </xsl:apply-templates> |
<xsl:call-template name="Qname"/> |
<xsl:with-param name="QName" select="expression"> sequence-constructor </xsl:with-param> |
<xsl:function name="QName"> xsl:param*, sequence-constructor* </xsl:function> |
<xsl:value-of select="expression"> sequence-constructor </xsl:value-of> |
<xsl:variable name="QName" select="expression"> sequence-constructor </xsl:variable> |
<xsl:copy> sequence-constructor </xsl:copy> |
<xsl:copy-of select="expression"/> |
<xsl:if test="expression"> sequence-constructor </xsl:if> |
<choose> xsl:when*, xsl:otherwise? </choose> |
<xsl:when test="expression"> sequence-constructor </xsl:when> |
<xsl:otherwise> sequence-constructor </xsl:otherwise> |
<xsl:for-each select="expression"> xsl:sort*, sequence-constructor </xsl:for-each> |
<xsl:for-each-group select="expression" group-by="expression"> xsl:sort*, sequence-constructor </xsl:for-each-group> |
<xsl:sort select="expression" data-type="{string}"> sequence-constructor </xsl:sort> |
<xsl:key name="qname" match="pattern" use="expression"> sequence-constructor </xsl:key> |
<xsl:element name="{string}"> sequence-constructor </xsl:element> |
<xsl:text> character data </xsl:text> |
<xsl:attribute name="{string}" select="expression"> sequence-constructor </xsl:attribute> |
<xsl:attribute-set name="QName" use-attribute-sets="Qnames"> xsl:attribute* </xsl:attribute-set> |
<xsl:message> sequence-constructor </xsl:message> |
A reminder of the subset of the XSLT syntax used in our examples. Names in italics refer to other elements. Regular expression syntax is explained in Table B.1