Variables and Parameters
Once you have read this section,
you will have found out that its title is a bit deceptive. You, as a
programmer, have certain expectations about a new programming language when you
start learning it. One of them is that you expect it to be possible to store
values in variables, change them and retrieve them later. Although XSLT has an
element called variable, you actually cannot
do much with it. This may sound unbelievable, but it is a result of the way
XSLT works that you cannot have variables. This is a thing that beginning XSLT
programmers have many difficulties grasping.
A variable in XSLT is really not what we would call a variable in VB, but more
like a constant. The syntax for declaring a variable is like this:
Or you can declare it like this:
These syntaxes are equivalent, but note that the first
example uses an XPath expression and the second one uses an included fragment
of XML. This causes the first variable to hold the numeric value 2 and the
second one the string value '2'.
The value of a variable can be used in expressions
and attribute value templates. The reference to a variable's
value is done with $variablename, for example:
The copy-of element is a convenient way
to insert the value of a variable into the output document.
A variable can be used both as a top-level element (child
of the stylesheet
element) and at template level (descendant of a template
element). As a top-level element, the variable can be used from any place
in the document. Within the template, the variable can be seen by all elements
following the declaration (and their descendants).
In conclusion, the variable element doesn't really live
up to its name, because it cannot change. There is no way to change the
content. This is done by design. The XSLT specification does not want to
specify any order for the evaluation of different nodes. By introducing
changing values, it would become relevant for the result whether a certain
action is performed before or after the change.
The param element works very much like
element. The param
element has a name
attribute and a select attribute, but the select
attribute on the param element is only a default value. If a value is
passed, this replaces the value in the select attribute.
Passing a Parameter to a Template
If a template has a parameter defined, a value
can be passed when the template is executed (by apply-templates or call-template).
Suppose you have this template:
If you call it using call-template, its index number would be formatted numerically (1. ).
But we could also have the same template output the number in another format
using the parameter format (which is used in the attribute value template in
the number element):
<xsl:if test="@count = 'alpha'">
<xsl:with-param name="format" select="'a. '"/>
This template will match on LI elements that have an OL parent. The transformation of these elements is
implemented in the template 'numbered-item'.
Only if the matched element has a count
attribute with value 'alpha' does
the template get called with a passed parameter value. This will cause the
called template to output the number of the element in another format.
The with-param element can be used as a child of call-template and apply-templates. The name must
be specified; the value can also be specified with the content of the element
(just like the variable and param elements can).
Passing a Parameter to a Stylesheet
Although the XSLT specification defines a way to declare global parameters, nothing is mentioned
about passing a parameter to the stylesheet. This depends on the implementation
of the library you use. The SAXON and XT implementations both allow passing
parameters on the command line. In the developer's preview of MSXML, you can
set a parameter to a stylesheet only by using the special XMLDOMXSLProcessor object. This object is new in
the MSXML library and is intended to cache compiled stylesheets to improve
performance for repeated transforms with the same stylesheet. If your
stylesheet contains a parameter called $x, the following code could be used
to make the transformation:
Dim oDoc as new MSXML2.DOMDocument
Dim oXSLT as new MSXML2.DOMDocument
Dim oResult as new MSXML2.DOMDocument
Dim oTemplate as new MSXML2.XSLTemplate
oXMLDOMXSLProcessor as new MSXML2.XMLDOMXSLProcessor
oDoc.async = false
oXSLT.async = false
Set oTemplate.stylesheet =
Set oXMLDOMXSLProcessor = oTemplate.createProcessor
Set oXMLDOMXSLProcessor.input = oDoc
Set oXMLDOMXSLProcessor.output = oResult
"Value we want to pass in")
There are quite a lot of objects that we need here, three DOMDocument
objects for starters. One of them may be empty. It is the target for the
The second one contains the source document (oDoc) and the third one contains the
is used to build the right template object. This template is used to create an XMLDOMXSLProcessor
object. We inform the processor about the input and output documents, and then
finally add our parameter value and let it transform. As this library is by no
means stable at the time of writing – it is only a preview after all – it is
very possible (so indicates the preliminary documentation) that the syntax will
be different in the final release. In any case, the functionality of passing
parameters will be included in that release.
Top Level Settings
The top-level settings are a set
of elements that can only be used at the top level of an XSLT document, and
hold settings that specify how the stylesheet should be used. They specify the
behavior of the processor on a few points.
The output element is a bag of attributes that
indicate settings about the style of output that is generated. The main setting
is defined in the method attribute. The possible values are xml,
If the method is set to xml, the output document will be an XML document. What this means depends largely
on the other attributes of the output element:
The version attribute specifies which
version of XML should be used – we only have version 1.0 now, but that will
probably change in the future. This number will also appear in the XML
declaration if one is generated. The default version is 1.0.
The encoding attribute sets the preferred
encoding for the destination document. If it is not specified, XSLT processors
will use UTF-8 or UTF-16. If an XML declaration is generated, this will contain
the encoding string specified.
The indent attribute can be set to yes
to allow the processor to include additional white space in the destination
document. This can improve readability. The default setting is no.
The attribute cdata-section-elements tells the
processor when to use CDATA sections in the destination and when to escape
illegal characters by using entity references. The value can hold a white space
separated list of element names. Text nodes that have a parent node in this
list will be output as CDATA sections. All others will be
escaped (characters like < will be replaced by entities
omit-xml-declaration can be set to yes
to leave out the XML declaration. By default, XSLT will include one, reflecting
the settings of encoding and version. Also, if the standalone
attribute has any value, this value will show up in the XML declaration.
With the doctype-system and doctype-public
attributes, the validation rules for the destination document can be set. If
you use only doctype-system,
the processor will include a <!DOCTYPE fragment just before the
first element. The doctype will be the name of the root element. The system
identifier (URL of the DTD) is the value of the doctype-system
attribute. If you also specify a doctype-public attribute, the output
will contain a doctype
declaration referring a public DOCTYPE, with the value of doctype-system
as its URL. If only doctype-public is used, it will be ignored.
Finally, the media-type attribute can be used to
specify a MIME-type for the result. By default this is text/xml,
but some XML-based document types may have their own MIME types installed.
If the method attribute on the output
element is set to html, the results of some of the other attributes change
a bit compared to the xml method.
The version attribute now refers to the
version of HTML, with a default value of 4.0. The processor will try to make
the output conform to the HTML specification.
Empty elements in the destination document will be
outputted without a closing tag. Think of HTML elements like BR,
Textual content of the script
elements will not be escaped. So if the XSLT document contains this literal
<script>if (a > b)
This will be output as:
<script>if (a > b)
If any non-ASCII characters are used, the processor
should try to use HTML escaping in the output (ë
instead of ë).
If an encoding is specified, the processor will try to
add a META
element to the HEAD
of the document. This will also contain the value for media-type (default is text/html).
If the method attribute is set to text,
the output will be restricted to only the string value of every node. The media-type
defaults to text/plain,
but you can use other MIME types. Think of generating RTF documents from an XML
source document. These have no XML mark up, so the most appropriate method is text,
set to application/msword.
The encoding attribute can still be used, but the default value is system
dependent (on most Windows PCs it will be ISO-8859-1).
Let's have a look at an example. The following stylesheet is used:
This is literal text with an ëxtended character
We use this stylesheet on an arbitrary, valid XML document.
Note that the output will always be the same literal XML tree. We will now only
change the output method and have a look at the result. First the result for
<?xml version="1.0" encoding="utf-8"?>
<TEST>This is literal text with an
Note that every element starts on a new line. This is the
result of the indent="yes"
attribute. If this had not been specified, all content would be concatenated on
one line. This XSLT processor has defaulted its output to encoding UTF-8. UTF-8
supports the extended character ë, so this is not escaped.
Setting the method to html would generate:
<TEST>This is literal text with an
Note that the XML declaration has disappeared and the processor
appears to have decided on a slightly different formatting around the TD
elements. The processor has been assigned to indenting the resulting document,
but in html
mode, this may only be done in places that cannot influence the appearance of
the document in a browser. Also, the ë character cannot be used in HTML, so it
is escaped using the preferred HTML entity ë (not the numeric XML
Using the text method, the result would be:
This is literal text with an ëxtended
Cell dataSecond cell
Only the string values of the nodes have been printed. The
specified encoding is used, so the special character is no problem. Note that
no white space appears between the values of the two TD
elements. We will see more on white space in the next sections.
strip-space and preserve-space
What exactly happens to the white space in a document and in the XSLT document
itself? This is one of the subjects that often puzzle XML developers. Spaces,
tabs and linefeeds seem to emerge and disappear at random. And then there are
the XSLT elements to influence them: strip-space, preserve-space
and the indent
attribute on the output element. Let's take a closer look.
During a transformation, there are basically two moments
when white space can appear or vanish:
When parsing the source and stylesheet documents and
constructing a tree.
Encoding a generated XML tree to the destination document.
Before any processing occurs, the XSLT processor loads the
source and stylesheet into memory and starts to strip unnecessary white space.
The parser removes all text nodes that:
consist entirely of white space characters.
have no ancestor node with the xml:space
attribute set to preserve.
are not children of a white space-preserving element.
For the stylesheet, the only white space preserving parent
element is xsl:text.
For the source element, the list of white space preserving elements can be set
using the strip-space
elements from the stylesheet. By default, all elements in the source document
preserve white space. With the elements attribute of strip-space,
you can specify which elements should not preserve white space. Adding elements
to the list of elements that have their white space preserved is done with preserve-space.
attributes accept a list of XPath expressions. If an element in the source
matches multiple expressions, the conflict is resolved following the rules for
conflicts between matching templates.
So if a stylesheet contained these white space elements:
The processor would strip all text nodes in the source
document, except for those inside a PRE element or a CODE
After stripping space from the source and stylesheet
documents, the processing occurs. The generated tree of nodes is then persisted
to a string or file. By default, no new white space is added to the result
document, except if the output element has its indent
attribute set to yes.
On document level, it is possible to define certain groups
of attributes that you need to include in many elements together. By grouping
them, the XSLT document can be smaller and easier to maintain:
Here the attribute-set element defines a group
of two attributes that are often used together. In the template for chapter
headings, the attribute-set
is applied to a literal element, but use-attribute-set can also be used on
elements. Be careful not to use use-attribute-set by itself (directly
or indirectly), as this would generate an error.
The namespace-alias element is used in very special cases, especially when
transforming a source document to an XSLT document. In this case, you want the
destination document to hold the XSLT namespace and lots of literal XSLT
elements, but you don't want these to interfere with the transformation
process. See the problem? You are shooting yourself in the foot there.
Using namespace-alias, you can use another
namespace in the stylesheet, but have the declaration for that namespace show
up in the destination document with another URI:
Instead of declaring the literal XSLT output elements in
their real namespace, they have a fake namespace in this document. In the
destination document, the same prefixes will be used, but they will refer to
The key element is a very special one. It
will take a little time to discover
its full potential. It is more or less analogous to creating an index on a
table in a relational database. It allows you to access a set of nodes in a
document directly with the key() function, using an identifier
of that node that you specify. Let's describe an example. We could, using the key
element, define that the key person-by-name gives us access to PERSON
elements by passing the value of their name attribute. If the key
is set up correctly, we would use key('person-by-name', 'Teun')
to get a result set of PERSON elements that have their name
attribute set to 'Teun'.
To set this key, you would have used the element like this:
Try to see what each of the attributes name,
specifies. The name
attribute is simple: it just serves to refer to a specific key of which there
may be many. The match attribute holds a pattern that nodes must match to
be indexed by this key; this pattern is identical to the template match
attribute. It is not a problem if the same node is indexed by multiple keys.
For each node in the selected set, the XPath expression in the use
attribute is evaluated. The string value of the result of this expression is
used to retrieve the indexed node. Multiple nodes can have the same result when
in their context. When the key function is called with this
value, it will return a result set holding all nodes that had this result. The
result can be a node set. In this case, each of the nodes will be converted to
a string and each of these strings can be used to retrieve the selected node.
Don't worry if you can't see the point of this yet. We will
do an extensive example on this. Suppose we have this XML document:
You are transforming the XML source with an XSLT document
that starts like this:
If you now use the key() function, your results will be:
Expression Used in key()
Both PERSON elements with name="Peter"
Only the Peter that has children
Both Peters, because Peter
is one of the traditional names in the family
Now what are the cases where
using a key is a good idea? Think of situations where XML elements often refer
to each other using some sort of ID, but without using the validation rules for
IDs (because these are sometimes too rigid). The key
keep your code more readable.
depending on the implementation, which may help
performance. The XSLT processor can keep a hash-table structure in memory of
all key references in the source document. If these references are often used,
performance gains can be substantial.
XSLT has defined a set of built-in functions that can be used in expressions. These are complementary to the
functions already available through XPath. These XPath functions include string
functions like starts-with(),
numeric functions like sum() and others like id().
These have been covered earlier in this chapter. We will not describe all
available XSLT functions here; we will just select a few. You can find all
functions in Appendix D.
format-number(number, string, string)
The format-number function converts the numeric first argument to a string. To do this, it
uses the second argument as a format specifier and the third (optional)
argument as a reference to a decimal-format element. First, we
will look how the function behaves if we do not specify our own decimal
formats. Say we leave the third parameter out. The format that we can pass to
the second parameter can hold two formats at a time: one for positive numbers,
one for negative numbers. They are separated by the semicolon. The format
is built up from these special characters:
digit, hides leading and
multiply by 100 and show
multiply by 1000 and show
any other character can
serve as prefix or suffix
So using this function would give the following results:
Different countries use different characters for separating
the decimal part of a floating-point number from the integer part and for
grouping the digits. That's why XSLT allows you to change the special characters
to other symbols. This can be done by including an xsl:decimal-format
element as a top level element in your document. The format-number
function can refer to this decimal format by name. Consider this example:
name = qname
decimal-separator = char
grouping-separator = char
infinity = string
minus-sign = char
NaN = string
percent = char
per-mille = char
zero-digit = char
digit = char
pattern-separator = char />
The name attribute is for referring to the
format from a format-number
function. All other attributes are for overruling the default character. This
new character must be used in specifying the format string and will also be the
select="format-number(1567.8, '#.###,00', 'numfrmt')"/>
The output of this stylesheet will be 1.567,80.
The current() function returns the current context. This can be very useful inside subqueries in
XPath expressions. It allows you to make constructs in an XPath expression that
are similar to SQL inner joins, combining and comparing values from different
contexts. Suppose we have this XML document:
<title>Dancing in the street</title>
<title>State of shock</title>
We want to generate a list of all songs in the collection
with their artists, but for every artist we want to include a link to the other
songs in the collection that the artist performs. We will make the list in
HTML, creating links from the artist's songs to the entry of that song. To do
this, we use a template for the artist element like this:
select="//Song[artist/text() = current()/text()]
[title != current()/ancestor::Song/title]
It generates a piece of XML looking like this:
<a href="#Song4">Knock on
The essential part here is the XPath expression in the for-each
element. It selects the set of all song elements and filters the set by
introducing two predicates.
The first predicate: [artist/text()
checks if the text of the artist element (relative to the
element) is equal to the text of the current context. The current context is
the context of the for-each element, not the context of the predicate. This
will select those song elements that have an artist
element with the same name as the current artist. This will include the current
song (which obviously has the same title as the current song).
The second predicate: [title
checks if the title of the predicate's context (a song
element) is equal to the title of our current context's song ancestor. The
element is included in the filtered set if the titles are not equal. The
function of this predicate is to remove the song itself from the list of references
to other songs. The complete stylesheet, called artist.xsl,
can be downloaded from the Wrox web site.
The document() function is specified to combine information from
several documents into one destination document. Suppose you have a directory
with a load of articles in XML format. All have references to other documents
in the same directory. The part that defines the references to other articles
<Author>Teun Duynstee </Author>
<Title>An interesting article </Title>
<Intro> ... </Intro>
<Body> ... </Body>
<Item type="URL" loc="http://www.asptoday.com/art2">Some
<Item type="local" loc="2"/>
As you can see, there are two kinds of references;
references by URL and local references. The local references point to other
articles of the same format in the same directory. The files are called art1.xml,
etc… The local reference in the example refers to art2.xml
(indicated by loc="2").
What we would like to do now is to generate HTML documents
that display a styled version of the XML article. The referenced articles are
particularly tricky. We want them to appear like this:
Some other article [external]
A great article (by: James Britt)
Note how the first article is displayed using only content
from within the source document, while the second reference displays data about
the referenced document that is not available in the source (the title and
author). How is this done?
(by: <xsl:apply-templates select="document(concat('art', @loc,
The template for Item elements is split into two
parts. The first part is executed if an Item has type='URL'.
This generated an HTML link with the loc attribute as its href
attribute and the contained text as its title. This is simple – we've done this
before. Note the use of an attribute value template in the literal element a.
The second part of the template is more interesting. If the
type of the reference is local, then the href
is constructed in a specific way, concatenating a string together. Now for the
title of the referred document: from the select attribute of a value-of
element, we call the document function, passing it the relative URL and a
small XPath expression, indicating the fragment that is referred to. The result
is that the value-of
action is executed on the title of the referred document, effectively
outputting the content of the title element. After that, you see
being used with a remote fragment.
In this example, we used only one parameter, a string value.
It is also possible to pass in a node set. If you do so, the document()
function will convert all nodes to their string values and use these as URIs.
function then returns a node set of external documents. The second, optional,
parameter indicates the base URI to use for relative URI references.
The generate-id() function does just what you would expect: it generates a unique identifier. The
identifier is always a string of alphanumeric characters, making sure that it
can be used as an XML qualified name (think of filling an ID type attribute).
The identifier depends on the first element in the passed node set. If no node
set is passed, the context node is used. The implementation is free to choose
any convenient way to generate a unique string, as long as it is always the
same string for the same node.
For very simple stylesheets that consist of only one template matching the root, a
special simplified syntax is specified. In this simplified syntax, the whole
document is the content of the template. The stylesheets that can use this
simplified syntax are often doing transformations, mostly consisting of
literals defining a template document. Only a few values from the source
document are entered in specific locations.
The XML documents defining an
article's content could be transformed by this stylesheet: