apply-templates
The xsl:apply-templates
element is the most typical example of
a command element (an element that starts the processing of a node). Because
it is so important, we have already covered it before. However, there are more
ways to invoke another template.
apply-imports
When we described the import
element, we saw that sometimes the
main XSLT document contains templates that match the same XPath expression as
one of the templates in the imported document. In these cases, the template
in the main document overrides the imported template. Using this feature, XSLT
authors can create new transformations based on existing ones, extending them
with new templates or changing existing templates. If you are familiar with
object-oriented design, you will like this idea.
If you are overruling a template in your document, you will often want to invoke the original template from your newer implementation. Let's look at an example.
The source document contains data about books and the data about a book's author
is always coded in an AUTHOR
tag. A typical AUTHOR
tag looks like this:
<AUTHOR firstname="Teun" lastname="Duynstee" initials="L.W.A."
nobelprize="no"/>
Several different XSLT transformations exist in our organization, all dealing with book information. Some repeating transformations were put together in a stylesheet that is frequently imported into other XSLT documents. It looks like this:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<!—- many other templates -->
<xsl:template match="AUTHOR">
<xsl:value-of match="@firstname"/>
<xsl:text>
</xsl:text>
<xsl:value-of match="@lastname"/>
</xsl:template>
</xsl:stylesheet>
The template transforms any matched AUTHOR
attribute to a text
node consisting of the firstname
attribute joined to the lastname
attribute by a single space. In our sample source, the output would be something
like:
Teun Duynstee
Now we want to write an XSLT document that will transform XML data about a book into an HTML document. In the HTML document, the author's full name should appear, formatted in italics. We already have a transformation rule that creates the full name of the author, but it does no formatting. We can now import the standard author transformation and modify it slightly in our overriding template:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="booklib.xsl"/>
<xsl:template
match="AUTHOR">
<I><xsl:apply-import/></I>
</xsl:template>
</xsl:stylesheet>
The new template just specifies the literal element I
that will
cause italic fonts in HTML, and inside the I
element, it calls
the template which it overrules from the import. The result would be this:
<I>Teun Duynstee</I>
call-template
The call-template
element is another element that can be used
to organize the templates in your document. For calling a template with call-template
,
the template must have a name
attribute. It works like apply-templates
,
but there is no change of context node. In fact call-template
is
very much like calling a function in a procedural programming language. Here's
an example:
<xsl:template name="fullname output">
<xsl:value-of match="@firstname"/>
<xsl:text> </xsl:text>
<xsl:value-of match="@lastname"/>
</xsl:template>
<xsl:template match="AUTHOR[@nobelprize='no']">
<xsl:call-template name="fullname output"/>
</xsl:template>
<xsl:template match="AUTHOR[@nobelprize='yes']">
<B>
<xsl:call-template name="fullname output"/>
</B>
</xsl:template>
The two templates for AUTHOR
elements (for Nobel prize winners
and others) both call the same template for formatting the attributes into a
full name string.
If a template is called by name the match
attribute is ignored
and vice versa.
What if Several Templates Match?
If the XSLT processor is searching for a template to use for transforming a certain node, it's possible that it will find several templates that match (and are of the same mode – check the following section on 'Modes'). The XSLT specification defines a set of rules to determine which template is the most appropriate. These rules are quite complex, but the general idea is not so hard to understand. In order of increasing importance:
- An imported template is less important than one associated with the document (i.e. not imported).
- The template imported later is more important than one imported earlier.
- A high priority template is more important than a low priority template.
- A more specific
match
attribute is more important than a more general matching expression.
When the processor starts searching for an appropriate template, it first creates a set of all available templates. From this set, it removes all templates that don't match. After that it removes templates that have a lower import precedence than others. When several documents are imported, and especially when imports are nested, things can get rather complicated. What the processor does is to build a tree of imported documents. Suppose Document A imports B and C (in that order), B imports D and C imports E, the tree would look like this:
|
Note how Document B is lower in the tree than Document C. This is because imports that occur later in the document prevail over imports done before. The higher in the tree a document is (in an absolute sense, not in a hierarchical sense), the higher the import precedence. The built-in templates are treated as if they are imported at the very beginning of the main document and therefore have the lowest priority of all.
If several templates remain (i.e. there is more than one matching template
in the same document), the template with the highest priority is chosen. The
priority of a template can be set using the priority
attribute
on the template element. This attribute can have any numeric value, both positive
and negative. If the priority
attribute is not set, a default priority
is calculated for the template. This default priority depends on the match
attribute. It is always a value between –0.5 and 0.5. Priority values are assigned
as follows:
Kind of Pattern |
Examples |
Priority |
Specified name along the |
|
0 |
Unspecified name along the |
|
-0.25 |
Only a node test |
|
-0.5 |
All other cases |
|
0.5 |
If several templates exist in the same document with the same priority it causes
an error, but most XSLT processors will not stall but will instead pick the
one nearest to the bottom of the document. This happens quite often. In many
cases, developers use no priority
attributes. Because many matching
patterns cause a priority of 0.5, templates with the same priority will no doubt
occur.
Modes
If you need to have some templates used in some special cases, but not always,
you can try using different modes. The mode
attribute is an optional
attribute on both the template
and apply-templates
elements. By calling apply-templates with the mode
attribute set,
you instruct the processor to use only templates that have the same mode
attribute. This way, you can create several sets of templates that don't interfere
with each other. Each mode also has its own built-in templates.
Looking at the code sample below, we have two templates now that both match on AUTHOR, but one is in the default mode and the other one in the formal mode:
&l
Comments