Using XML Queries and Transformations

Commands

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 child or attribute axis

child::PARA

TITLE

@fullname

0

Unspecified name along the child or attribute axis

*

attribute::*

-0.25

Only a node test

node()

text()

processing-instruction()

-0.5

All other cases

PARA/LINE

preceding::*

*[@*='yes']

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

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.” - Antoine de Saint Exupéry