Maintained by: David J. Birnbaum (djbpitt@gmail.com) Last modified: 2022-10-31T21:16:58+0000
This supplementary XSLT tutorial concentrates on four topics: variables, keys, conditionals
(<xsl:if>
and
<xsl:choose>
), and the difference between push
processing (<xsl:apply-templates>
and
<xsl:template>
) and pull processing
(<xsl:for-each>
and
<xsl:value-of>
).
<xsl:variable>
elementIf you’ve used variables in other programming languages before, be aware that variables in XSLT do not work like variables in most other languages. The value of a variable in XSLT cannot be updated once the variable has been declared.
The <xsl:variable>
element requires a
@name
attribute, which names the variable for future
use. The value of the variable is typically assigned through a
@select
attribute (in which case
<xsl:variable>
is an empty element, e.g.,
<xsl:variable name="author" select="'William Shakespeare'"/>
),
but it can also be specified as the content of the
<xsl:variable>
(in which case the element cannot
have a @select
attribute, e.g.,
<xsl:variable name="author">William Shakespeare</xsl:variable>
).
It’s usually easier to use @select
, since this
typically produces less complicated code, but if you need to do anything particularly
involved, you may not be able to use the @select
method
of assigning your value. To reference a variable later on, precede the name with a dollar
sign, that is, use $variableName
, where
variableName
is the value of the
@name
attribute you wrote when creating the variable.
For example, when you declare a variable to, say, count the paragraphs
(<p>
elements) in your input, you might give it the
name paragraphCount
with something like:
<xsl:variable name="paragraphCount" as="xs:integer" select="count(//p)"/>
Note that there is no leading dollar sign associated with the name when you declare and define a variable. But should you later refer to the variable, you need the leading dollar sign. For example, to get the value of the variable, you might use:
<xsl:value-of select="$paragraphCount"/>
The @as
attribute is technically optional, but there
are situations where omitting it can produce unwanted behavior, we use it consistently in
our own work, and it is required for all variable definitions in this course. Common values
for @as
when setting variables equal to atomic values
are xs:integer
,
xs:double
(non-integer numbers),
xs:decimal
(non-integer numbers where exact precision
mattters, as in dollar-and-cents notation). You can also set variables equal to one or more
nodes; for example:
<xsl:variable name="allParagraphs" as="element(p)*" select="//p">
sets the value of the variable $allParagraphs
equal to
a sequence of all <p>
elements in the document. The
@as
values accept the same repetition indicators as
Relax NG: no repetition indicator means exactly one item, a question mark means zero or one,
a plus sign means one or more, and an asterisk means zero or more.
The <xsl:variable>
element may be defined in
different locations in the stylesheet, and the location makes a difference. When you define
a variable (that is, use the <xsl:variable>
element)
as an immediate child of the root <xsl:stylesheet>
element, the variable becomes available for use anywhere in the stylesheet. This is called a
stylesheet variable (comparable to what other programming languages call a
global variable). When, on the other hand, you define a variable inside a
template rule, it’s available only within that template rule. Where a variable is available
is referred to as its scope, and the general rule is that variables are scoped to
all descendants of their parent. For example, if the parent is a template rule, the variable
is available anywhere inside the template rule, but not outside.
We often use a top-level <xsl:variable>
element to
avoid having to recalculate a value that is used frequently, as well as to access the tree
from an atomized context (such as when you've used
<xsl:for-each>
, which we’ll explain when the
situation arises). You might also use variables just to improve legibility, that is, to
avoid typing a long XPath expression within some other complicated instruction. Variables
that are not strictly necessary and that are created for the convenience of the developer
are called, not surprisingly, convenience variables.
For more information about variables, see Michael Kay, 500 ff.
<xsl:key>
element<xsl:key>
may be overlooked in situations where
comparable functionality is available through other means, but it is often simpler (and
almost always faster) to use <xsl:key>
than the
alternatives (we once reduced the run time for a transformation from twenty minutes to just
a few seconds by switching to an implementation that used
<xsl:key>
!).
<xsl:key>
is an empty element that requires three
attributes. Consider, for example, XML structured like:
<book>
<title>XSLT 2.0 and XPath 2.0 programmer’s reference</title>
<author>Michael Kay</author>
<publisher>Wrox</publisher>
<edition>4</edition>
<year>2008</year>
</book>
where you want to be able to find books by their authors. You could define a key as:
<xsl:key name="bookByAuthor" match="book" use="author"/>
The three required attributes in this case are:
@name
attribute is the name you’ll use when
referring to the key when you need to use it to look up and retrieve a value. Since you
can define multiple keys, giving each one a distinct name makes it possible to select the
one you care about when you use it to look something up. You can make up your own value
here, but the syntax we’ve used is a common strategy for reminding the human operator of
what the key retrieves and how it finds what it’s looking for.@match
attribute is an XPath pattern—like the
@match
attribute on
<xsl:template>
or the
@context
attribute on a Schematron
<sch:rule>
element. Here we say that we want to find
<book>
elements. Note that because this is an
XPath pattern, and not a full XPath expression, all we need is the name of the element.
This is similar to specifying an XSLT template rule that is supposed to process
<book>
elements no matter where they appear, which
would have a @match
attribute value of just
book
. In both cases, the key and the template don’t
need (= should not be given) a full path to the elements to which they apply; they need
only enough information to know what to match, and in this case the bare element name will
suffice.@use
attribute is an XPath expression starting
at the value of the @match
attribute, that is, that
uses the value of the @match
attribute as the
current context item. In this example, we are saying that we want to find
<book>
elements by using their child
<author>
elements. That is, the XPath expression
that constitutes the value of the @use
attribute
takes the value of the @match
attribute as its
starting context, so if the value of @match
is a
<book>
element, a
@use
value of
author
means to look at any
<author>
elements that are on the child axis of
<book>
elements.The @match
attribute value of the key is the object
(typically an element) that the processor will return when the key is referenced (see
below), while the @use
attribute value tells the
processor what to use to look up those values. In the example above, you would be able to
use the key to retrieve <book>
elements according to
their <author>
child elements. To retrieve
information with the help of a key, you use the key()
XPath function, which takes two or three arguments. The first argument is the name of the
key (matching the @name
value from the
<xsl:key>
element), and it must be in quotation
marks (single or double). The second argument is the value to look up; for example, in the
sample above, if you were to specify Michael Kay
as the second argument to the
key()
function
(key("bookByAuthor","Michael Kay")
), you would retrieve
all <book>
elements with
<author>
children that have the value Michael
Kay
. The (optional) third argument is the document root of the document in which to
look. When the third argument is omitted, the function searches in the current document,
which is what we want to do most often. For further discussion of
<xsl:key>
, consult Michael Kay, page 376.
<xsl:if>
<xsl:if>
is useful when you treat the same node
differently under different circumstances. For example, you might use
<xsl:if>
to color all
<speaker>
elements with the
@who
value Hamlet
differently from all other
<speaker>
elements. For that sort of task, you
would have a templates that matches all <speaker>
elements and inside it you would test the value and do something extra if the value is
equal to the string Hamlet
.
<xsl:if>
takes a required attribute
@test
, which is an XPath expression that evaluates to
a Boolean value (either True or False), just like a predicate expression in
XPath or a @test
attribute on
<sch:assert>
and
<sch:report>
in Schematron. The contents of the
<xsl:if>
element, then, describe what the system
is to do if the result of @test
is True: for example,
you might want to apply templates or use
<xsl:value-of>
to display the results of a
particular function, or you might want to create a special
@class
attribute value (if you are generating HTML)
using <xsl:attribute>
that can be styled with CSS
(see our Using
<span>
and
@class
to style your HTML to refresh your
memory about the @class
attribute). Consider:
<xsl:template match="sp">
<p>
<xsl:if test="speaker='Hamlet'">
<xsl:attribute name="class">mainCharacter</xsl:attribute>
</xsl:if>
...
</p>
</xsl:template>
In this example we are checking each <sp>
(because we’re doing this inside the template rule for
<sp>
elements) to see whether its child
<speaker>
(remember that we default to the child
axis) is equal to the string Hamlet
. If the result of this test is True, we’ll go
on to perform whatever is inside <xsl:if>
. If it
isn’t, we won’t do anything special with it. In this case, everywhere this test is True
we’ll create an attribute using <xsl:attribute>
,
and we use the @name
attribute to specify what name
this attribute should have: in this case we’re creating the attribute
@class
. This attribute gets attached to the parent
element: in this case, <p>
. The contents of
<xsl:attribute>
indicate the value to be assigned
to this new attribute: in this case the value of
@class
will be mainCharacter
. This means that
anywhere there’s a speech by Hamlet, we’re mapping it to something like:
<p class="mainCharacter"> … </p>
If we then have a rule in our CSS like:
.mainCharacter { color: red; }
any <p>
element that contains a speech by Hamlet
will have this attribute and will now be colored red.
<xsl:choose>
<xsl:if>
is useful to trigger special behavior
under specific individual circumstances, such as whether a speech is or is not by Hamlet,
but sometimes we need to code for alternative possible conditions, or we care about what
should happen when the results of our conditional are False, and this is where
<xsl:choose>
comes in.
<xsl:if>
can run only one test and can have only
one result action, which it performs if the test evaluates to True. On the other hand, you
can use <xsl:choose>
to specify a number of
alternative conditions, as well as a fallback action if none of the conditions is True.
<xsl:choose>
takes at least one child
<xsl:when>
element (and up to as many as you want)
and one optional <xsl:otherwise>
element.
<xsl:when>
requires the same type of
@test
attribute that we discussed above for
<xsl:if>
. Since
<xsl:otherwise>
is the fallback condition, it
doesn’t take this @test
attribute; it applies only
when all <xsl:when>
tests return False.
Here’s an example that does one thing with Hamlet’s speeches, a different thing with
Ophelia’s speeches, and third thing (the otherwise
) for speeches by anyone
else:
<xsl:template match="sp">
<p>
<xsl:choose>
<xsl:when test="speaker='Hamlet'">
<xsl:text>[Hi, Hamlet!] </xsl:text>
</xsl:when>
<xsl:when test="speaker='Ophelia'">
<xsl:text>[Hi, Ophelia!] </xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>[Neither Hamlet nor Ophelia] </xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates/>
</p>
</xsl:template>
In this example, we have two tests (<xsl:when>
)
and one fallback (<xsl:otherwise>
), which is used
if neither test returns True. The first test checks whether the child
<speaker>
element (remember that we’re in the
template rule for <sp>
) is equal to Hamlet
.
If it is, we use the <xsl:text>
element to create
a text node with the content [Hi, Hamlet!]
, which means that we return the plain
text: [Hi, Hamlet!]
. The second test works along the same lines, except that it
checks whether the child <speaker>
is equal to
Ophelia
. If this test is True, then we return plain text reading [Hi,
Ophelia!]
. If neither of these tests returns True (that is, if the speaker is
anyone other than Hamlet or Ophelia), then the
<xsl:otherwise>
condition kicks in. In this case,
that means that we return the plain text [Neither Hamlet nor Ophelia]
. Note that
we’ve put in a space at the end of each of these strings of plain text because we apply
templates at the end of this block of conditionals in order to output the speech, and we
want a space before it. If you run this code, your output should look like this (we’ve
added bolding to the speaker names to make them easier to see here):
[Neither Hamlet nor Ophelia] Osric: It is indifferent cold, my lord, indeed.
[Hi, Hamlet!] Hamlet: But yet methinks it is very sultry and hot for
my
complexion.
<xsl:if>
and
<xsl:choose>
An <xsl:if>
element is equivalent to an
<xsl:choose>
that has exactly one
<xsl:when>
child and no
<xsl:otherwise>
. In that case it’s obviously
better to use <xsl:if>
because it says what it
means more directly and clearly than the alternative.
If you have multiple <xsl:if>
elements, one
after another, they all fire, while the options in
<xsl:choose>
are mutually exclusive, which means
that as soon as one test is true, the others are abandoned. If all you want to do is
style Hamlet’s speeches one way and Ophelia’s speeches a different way and do nothing
special for speeches by other candidates, you would get the same behavior from two
consecutive <xsl:if>
elements or from two
<xsl:when>
children of a single
<xsl:choose>
. In this situation you should use
<xsl:choose>
because the options are mutually
exclusive, so if a speech is by Hamlet, there’s no reason to test whether it’s by
Ophelia. Although you would get the same behavior from both approaches, the
<xsl:choose>
is easier to understand and more
self-documenting. (It is also more efficient computationally, although the difference in
processing time is unlikely to be noticeable with such a simple example.)
The examples above of <xsl:if>
and
<xsl:choose>
came from the following stylesheet,
which is included in its entirety for your reference. It outputs all of the speeches in
Bad Hamlet normally, but we have the system do some extra formatting
depending on whether the speaker is Hamlet, Ophelia, or anyone else. If you use it to
transform the play, you’ll see how the formatting works, and how new content is created
before each speech.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.w3.org/1999/xhtml"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="#all" version="3.0">
<xsl:output method="xhtml" html-version="5" omit-xml-declaration="no"
include-content-type="no" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<title>XSLT conditional practice</title>
</head>
<body>
<h1>XSLT conditional practice</h1>
<xsl:apply-templates select="//sp"/>
</body>
</html>
</xsl:template>
<xsl:template match="sp">
<p>
<xsl:if test="speaker='Hamlet'">
<xsl:attribute name="class">mainCharacter</xsl:attribute>
</xsl:if>
<xsl:choose>
<xsl:when test="speaker='Hamlet'">
<xsl:text>[Hi, Hamlet!] </xsl:text>
</xsl:when>
<xsl:when test="speaker='Ophelia'">
<xsl:text>[Hi, Ophelia!] </xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>[Neither Hamlet nor Ophelia] </xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="speaker">
<strong>
<xsl:apply-templates/>
<xsl:text>: </xsl:text>
</strong>
</xsl:template>
<xsl:template match="l | ab">
<xsl:apply-templates/>
<xsl:if test="following-sibling::l or following-sibling::ab">
<br/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
As an alternative to using <xsl:if>
or
<xsl:choose>
to handle speeches by Hamlet
specially, you can use alternative templates, one to match speeches by Hamlet and one to
match all other speeches:
]]>
Both templates technically match Hamlet’s speeches, but the template with the predicate has higher priority, so it will process all of Hamlet’s speeches and the other template will process all speeches not by Hamlet.
Whether you use templates with different @match
values or the conditional elements <xsl:if>
or
<xsl:choose>
for this sort of subtype handling is
up to you. In our own work we usually favor
<xsl:if>
if the processing is largely the same and
the difference can be described with an isolated code snippet, and we use different
templates if the differences are more comprehensive. Templates are one of the most
distinctively and characteristically powerful yet simple features of XSLT, and becoming
comfortable with templates is an important aspect of learning to code idiomatically in
XSLT.
The XSLT processing model supports both push and pull design. The
push model, which is what we’ve been using exclusively so far, relies on
<xsl:apply-templates>
to identify what is supposed
to get processed where, but not to do the processing; the actual processing is handled by
<xsl:template>
elements. This is called push
because you push the elements and other components out into the stylesheet and rely
on the templates to grab the individual pieces and process them. For example, you don’t say
take all the paragraphs and paint them blue
; what you do instead is say in one
place here are some paragraphs; take care of them
and in another whenever you
happen to run into a paragraph, paint it blue.
The great strength of push processing
is that you don’t have to know the structure of your input document—that is, you don’t have
to know which elements will be encountered where. The declarative template rules ensure that
no matter where an element pops up, you’ll have a template around that will know what to do
with it. Since the structure of humanities documents involves a lot of variable mixed
content, this declarative approach creates a flexibility that is difficult to achieve with
the sort of imperative programming that requires you to know at each moment exactly what is
supposed to happen next.
The pull model, on the other hand, is imperative in nature, and relies primarily on
<xsl:for-each>
and
<xsl:value-of>
. Pull processing is helpful when you
need to round up specific information, instead of dealing with it on the fly whenever it
happens to come up. Pull processing is useful, for example, if you want to count the
speeches for each character in a play. In this case you don’t want to process each speech
where it occurs (to do that you would apply templates to
<sp>
elements); you want instead of get a sequence
of distinct speaker names (with distinct-values()
),
iterate over them (with <xsl:for-each>
), and count
the speeches by each of them in turn. The pull model would work poorly, on the other hand,
for rendering each speech as it occurs, since any speech could contain an unpredictable
variety of in-line elements, and push lets you deal with those as they arise, without having
to know in advance which ones to call for explicitly.
An alternative way to count the speeches for each character uses
<xsl:for-each-group>
. See Kay pp. 326 ff.
Pull design is frequently overused by beginning XSLT programmers, especially if they have
experience with imperative programming. In many cases the end result of using pull will be
the same as the result of using push, but pull design is often harder to maintain because it
is less consistent with the declarative nature of XSLT as a programming language. With that
said, there are situations where pull design is the more appropriate choice, and the two
principal elements used in pull coding are
<xsl:for-each>
and
<xsl:value-of>
.
<xsl:for-each>
The <xsl:for-each>
element is used to iterate over
a sequence of items (nodes or atomic values). It requires one attribute,
@select
, the value of which is a full XPath expression
(just like the value of the @select
attribute with
<xsl:apply-templates>
). Whatever
@select
identifies becomes the sequence of current
context items, so any XPath expressions used in children of
<xsl:for-each>
begin at the current context node,
not at the document node.
This is an advanced detail that you’re welcome to skip over, but: Strictly speaking, <xsl:for-each>
mimics iteration, but it is not actually iterative, and since version 3.0 XSLT
provides an <xsl:iterate>
element that behaves in
a way that is more similar to how a for
loop operates
in imperative programming. Ask us if you’re curious about the details.
We often use <xsl:for-each>
with scalable vector
graphics (SVG), which we’ll be introducing later in the semester.
<xsl:value-of>
Although the results of <xsl:value-of>
and
<xsl:apply-templates>
are often the same, the real
usefulness of <xsl:value-of>
is that it allows you
to output, in a transparent and self-documenting way, both the results of functions and
non-node values, on the one hand, and the value of a node instead of the node
itself. Here is an example that produces a list of all distinct speakers in a play, without
duplicates:
<xsl:for-each select="distinct-values(//speaker)">
<li><xsl:value-of select="."/></li>
</xsl:for-each>
If you want to do something to every instance of a <speaker>
element in a play, though, repeats and all, you should prefer
<xsl:apply-templates>
. The difference is that each
instance of a <speaker>
element is a node in the
tree, but the sequence produced by applying the
distinct-values()
function to all of the
<speaker>
nodes is a sequence of atomic values, and
not of nodes.
The following example creates an HTML page that lists the number of speeches by each speaker in Bad Hamlet:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.w3.org/1999/xhtml"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xpath-default-namespace="http://www.tei-c.org/ns/1.0"
exclude-result-prefixes="#all" version="3.0">
<xsl:output method="xhtml" html-version="5" omit-xml-declaration="no"
include-content-type="no" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<title>Bad Hamlet Speeches</title>
</head>
<body>
<xsl:for-each select="//role">
<p>
<xsl:value-of select="."/>
<xsl:text>: </xsl:text>
<xsl:value-of select="count(//sp[contains-token(@who, current()/@xml:id)])"/>
</p>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Here we loop through each <role>
element in the
whole of Bad Hamlet (at any depth, as specified by the
//
at line 14) and create a
<p>
element for each one (lines 15–19). We know
(because that’s how cast lists work in TEI, and that’s one reason why we’re getting our
character list from the <role>
elements, instead of
by collecting and deduplicating <speaker>
elements
or @who
attributes) that the
<role>
elements are unique, so we don’t need to
deduplicate them. Inside each <p>
we return the
value of the context node; the node is represented by the
.
and the value is a distinct speaker name, as a string
(line 16). We then output a colon followed by a space, just as plain text (line 17). Finally
we return a count of all the <sp>
elements that meet
the condition of having a @who
value that contains the
@xml:id
of the speaker we are looking at at the moment
(line 18).
We use contains-token()
instead of testing for
equality because some speeches are uttered by more than one person, in unison, and we want
to count those toward the total for each of the speakers. We use
contains-token()
instead of the more familiar
contains()
because
contains()
will match on substrings, while
contains-token()
starts by atomizing its first
argument into whitespace-delimited word tokens (that is, words) and then tests only for
matches against complete tokens. In this document it happens to be that there are no
@xml:id
values on
<role>
elements that are subsequences of one
another, but that situation isn’t impossible, so we don’t make a risky and unnecessary
assumption. The contains-token()
function is new in
XPath 3.1, so it isn’t in Michael Kay, but it is in the more recent XPath function
references listed in the XPath section of our main course page.
The predicate in line 18 says get all the
When
we’re executing an <sp>
elements in the entire play and check to see whether their
@who
attributes contain some substring.<xsl:for-each>
loop, the value of
each item in the loop can be represented by current()
.
This means that we’re comparing the value of the @who
attribute of each <sp>
element to the
@xml:id
attribute of the
<role>
element that we’re processing at the moment.
For example, when we process
<role xml:id="Hamlet">Hamlet</role>
, we check
the @who
attribute of every
<sp>
in the play to see whether it contains, as a
substring, the value of the @xml:id
attribute of that
<role>
. If it does, that’s a speech by Hamlet, so it
gets included in our count. After we’ve gone through every
<sp>
and checked who the speaker is, we output the
count of the speeches for the <role>
we’re looking
at at the moment. Then we move on to the next
<role>
. When we run out of roles, the
<xsl:for-each>
terminates gracefully.
current()
This is the first time you’ve seen the function
current()
, and you may be wondering why you can’t
write:
count(//sp[contains-token(@who, ./@xml:id)])
(with a dot instead of current()
). The problem is that
the dot refers to wherever you are at that moment in your current XPath expression. Since
you’re inside a predicate that is being applied to a preceding
<sp>
, a dot would check the
@xml:id
attribute of the
<sp>
, and not of the
<role>
. Since the
<sp>
doesn’t have an
@xml:id
attribute (it’s the
<role>
that does), this wouldn’t find the matches we
care about. That is:
Inside a <xsl:for-each>
loop,
current()
refers to the current item in that loop.
In the case of <xsl:for-each select="//role">
,
current()
will refer to each
<role>
in turn.
The dot always refers to the current context in an XPath expression, which is the most recent path step, the one immediately before the predicate. For example, in:
//sp[contains(@who, ./@xml:id)]
the predicate immediately follows a path step that selects
<sp>
elements, so we would be testing whether
each <sp>
has a
@who
attribute that contains the value of the
@xml:id
attribute of that same
<sp>
. As noted above, this is wrong; we want to
look at the @xml:id
attribute of the
<role>
elements, and not of the
<sp>
ones.
You may find the following distinction helpful:
current()
refers to the current context at the XSLT
level and the dot refers to the current context in an XPath expression. At
the first step of an XPath path expression, the two mean the same thing. In the example
above, when we output <xsl:value-of select="."/>
we
could instead have said
<xsl:value-of select="current()"/>
, since in this
simple path the XSLT and XPath contexts are the same. We don’t have that choice in
count(//sp[contains(@who, current()/@xml:id)])
, though;
here the more complicated XPath includes a new step,
//sp
, which changes the XPath context. Here we need to
use current()
because the XSLT context was set at the
<xsl:for-each>
stage, and is unaffected by the
comparison. For more discussion, with examples, see Michael Kay, p. 735.
If you try to run this code, you’ll notice that it takes a bit longer than usual to finish.
That’s because it’s looping through the entire play repeatedly, looking at every speech once
for every role in the play. At 1137 <sp>
elements
and 37 <role>
elements, that’s 42069 comparisons.
This is part of why we usually avoid using
<xsl:for-each>
unless the problem really calls for
it, and in those cases there are ways to speed it up (such as by using a key, as described
above).
There are situations that can be managed with either push or pull strategies. In most of those cases, your instinct, unless you are a veteran XSLT programmer, will draw you toward pull. It’s much more common in humanities-oriented XSLT to use push programming, so where there’s a choice, we’d encourage you to train yourselves to think of push first, and fall back on pull only where it is truly more appropriate.