Chapter 7. Using Multiple Stylesheets

CONTENTS
  •  7.1 Working with External Stylesheets
  •  7.2 Template Rule Processing and Priorities
  • <xsl:include>

  • <xsl:import>

  • <xsl:apply-imports>

  • Conflict resolution for template rules

Up to this point in our discussion of XSLT stylesheets, we have talked about the stylesheet as the only file that contains all the templates that are being processed. XSLT also allows you to work with more than one stylesheet at a time.

The possibility of using multiple stylesheets and accessing their content selectively provides a means of grouping related template rules, packaging them together according to their function. For example, you may want to have a separate stylesheet that only handles tables, or one that handles list formatting. These separate stylesheets do not need to be physically incorporated into the main stylesheet. They can be called into use with one of two top-level elements, <xsl:include> or <xsl:import>.

In this chapter, we will address the two top-level elements, <xsl:include> and <xsl:import>, along with the related instruction element, <xsl:apply-imports>. We will also discuss the multiple ways in which conflicts between template rules can be resolved.

7.1 Working with External Stylesheets

Several elements in XSLT are used specifically to access stylesheets and template rules that are external to the current (or calling) stylesheet. These elements are <xsl:include> and <xsl:import>, which are the top-level elements used to bring in the external stylesheets, and <xsl:apply-imports>, which is an instruction element used specifically to choose an imported template rule over those in the current stylesheet.

7.1.1 The <xsl:include> Top-Level Element

The <xsl:include> element is used to access and incorporate the contents of another stylesheet into the current, or calling, stylesheet. It can be used anywhere in an XSLT stylesheet as long as it is a direct child of the <xsl:stylesheet> or <xsl:transform> document element. The <xsl:include> top-level element is an empty element, as shown in the following element model definition. It has one required attribute, href, whose value is a URI reference to an external stylesheet that will be included at the point of that the <xsl:include> element is used.

<!-- Category: top-level-element --> <xsl:include   href = uri-reference /> 

When the XSLT processor finds the XSLT stylesheet referenced by the href attribute's value, the top-level elements of that referenced XSLT stylesheet are inserted into the current stylesheet, literally in place of the <xsl:include> element. It inserts the entire included stylesheet minus its PI and <xsl:stylesheet> or <xsl:transform> document element as though it was originally part of the stylesheet in which the <xsl:include> element was invoked.

As an XML or SGML reference, the <xsl:include> element acts very much like an entity reference. When the parser sees the entity reference, it goes and resolves the entity and replaces the reference with the content of the entity.

7.1.1.1 Conditions Affecting Included Top-Level Elements

There are a variety of contingencies that can affect the behavior of included top-level elements when <xsl:include> is invoked, such as references to relative URIs in the included elements and namespace declarations from the XSLT stylesheet being included.

The simplest way to think of the included elements when <xsl:include> is invoked is to remember that they retain all the characteristics of their "home" stylesheet. The included top-level elements function like top-level elements of the including stylesheet to begin with, but they retain the relative paths in their URIs. For example, if the included elements reference a file in the home directory in which the stylesheet being included is found, it keeps the reference to that file's location. They also retain namespace declarations and any version, extension-element-prefixes, and exclude-result-prefixes of the home stylesheet.

The only exception is in the case of an <xsl:import> top-level element that is part of the included elements. What happens if one of the top-level elements being included is an <xsl:import> element? Following the rules for <xsl:import>, discussed in Section 7.1.2, the imported elements among the included elements of the XSLT stylesheet referenced with <xsl:include> are treated as though they were imported in the original stylesheet.

For example, if stylesheet main.xsl has an <xsl:include> element that points to included.xsl, and included.xsl has an <xsl:import> element that points to imported.xsl, then any top-level elements from xsl.imported will be treated as though they were referenced by an <xsl:import> element in main.xsl. The imported elements referenced by included.xsl "leap-frog" the stylesheet, importing them to behave as though they were in the original main.xsl stylesheet in which the <xsl:include> element that triggered this triple-chain was invoked in the first place. We will discuss this in more detail in the comparisons between <xsl:include> and <xsl:import> in Section 7.1.3.

7.1.1.2 Using the <xsl:include> Top-Level Element

The use of <xsl:include> enables an enterprise to boilerplate certain features of its stylesheets. Grouping stylesheets based on their functionality allows them to be shared and reused. For instance, in the ongoing series of examples with Markup City, we may need to have several different versions of an XSLT stylesheet, perhaps to prepare reports for several different agencies. This might be the case again with the area of town accessed via the <parkway>. Instead of several different stylesheets, which may be very large and difficult to maintain, we could have several modular stylesheets, each with its own title format. In Example 7-1 we show one such module stylesheet being included into a "main" stylesheet.

Example 7-1 Using <xsl:include> to add a separate stylesheet.
NPUT: <?xml version="1.0"?> <parkway>       <thoroughfare name="Governor Drive" />       <thoroughfare name="Whitesburg Drive">            <sidestreet name="Bob Wallace Avenue">            <block name="1st Street"></block>                  <block name="2nd Street"></block>                  <block name="3rd Street"></block>            </sidestreet>            <sidestreet name="Woodridge Street">            </sidestreet>       </thoroughfare>       <thoroughfare name="Bankhead Drive">            <sidestreet name="Tollgate Road">                  <block name="First Street"></block>                  <block name="Second Street"></block>                  <block name="Third Street"></block>            </sidestreet>            <sidestreet> Oak Drive </sidestreet>       </thoroughfare> </parkway> MAIN STYLESHEET: <?xml version="1.0"?> <!-- FILE NAME main.xsl --> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"            version="1.0"> <xsl:include href="audit.xsl" /> <xsl:template match="parkway">       <html>       <body>             <xsl:call-template name="doc-title" />       <dl>             <xsl:apply-templates/>       </dl>       </body>       </html> </xsl:template> <xsl:template match="sidestreet">             <dt>                    <xsl:value-of select="@name | text()"/>             </dt>             <dd><ul>                    <xsl:apply-templates select="block" />             </ul></dd> </xsl:template> <xsl:template match="block">       <li>             <xsl:value-of select="@name | text()"/>       </li> </xsl:template>       </xsl:stylesheet> INCLUDED STYLESHEET: <?xml version="1.0"?> <!-- FILE NAME audit.xsl --> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"                 version="1.0"                         > <xsl:template name="doc-title">       <center>             <h1>Prepared for the Auditor's Office</h1>             <h2>Borough of Monte Sano Boulevard</h2>       </center> </xsl:template> </xsl:stylesheet> 

The person running the scripts only needs to change one line, the <xsl:include> element in the main XSLT stylesheet, to include the correct stylesheet for the title for each report. Additional title stylesheets, as shown in Example 7-2, can be easily swapped out using the correct value for <xsl:include>.

For all intents and purposes, the main stylesheet and the included stylesheet are combined into one by the XSLT processor. After the first pass through the XSLT processor, which checks the basic logical structure of the XSLT elements for being a well-formed XML data instance, the <xsl:include> element URIs are resolved, or "looked up." The children of the document element of the included stylesheet in other words, its top-level element(s) are then inserted in place of the actual <xsl:include> element. This does not mean that the original XSLT stylesheet that used <xsl:include> has itself been transformed. Instead, to the processor's perception or, more accurately, parsing of the resulting XSLT stylesheet, there is a new template rule, extracted from the external stylesheet, in place of where <xsl:include> was to begin with.

7.1.2 The <xsl:import> Top-Level Element

The <xsl:import> top-level element is used to bring in elements from another stylesheet, similar to <xsl:include> discussed in the previous section. There are some basic differences between the two, however. The <xsl:import> top-level element must always come first among the children of the <xsl:stylesheet> or <xsl:transform> document element when it is used. Also, the templates found in an imported stylesheet have a lower precedence than templates found in an included stylesheet.

Example 7-2 Additional modular stylesheets for report titles.
OPTIONAL STYLESHEET 1: <?xml version="1.0"?> <!-- FILE NAME mayor.xsl --> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"                  version="1.0" > <xsl:template name="doc-title">       <center>             <h1>Prepared for the Mayor's Office</h1>             <h2>Borough of Monte Sano Boulevard</h2>       </center> </xsl:template> </xsl:stylesheet> OPTIONAL STYLESHEET 2: <?xml version="1.0"?> <!-- FILE NAME utilities.xsl --> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"                 version="1.0" > <xsl:template name="doc-title">       <center>              <h1>Prepared for the Water Utilities Office</h1>              <h2>Borough of Monte Sano Boulevard</h2>       </center> </xsl:template> </xsl:stylesheet> 

The <xsl:import> top-level element is an empty element, which is optional and repeatable. It has one required attribute, href, as shown in the following element model definition:

<!-- Category: top-level-element --> <xsl:import   href = uri-reference /> 

The <xsl:import> element uses its single required href attribute to retrieve the contents of an external XSLT stylesheet. The href attribute value is a URI pointing to another XSLT stylesheet.

Before addressing any elements in a stylesheet, the XSLT processor builds a tree of the stylesheet. All <xsl:import> elements are retrieved from the location specified in the href attribute and placed in the tree at the point where the <xsl:import> element was found in the original stylesheet. Once this stylesheet tree is built, the processor continues.

7.1.2.1 The Import Process

The use of <xsl:import> is essentially the same as given above for <xsl:include>, except that the imported elements come first in the importing XSLT stylesheet. This does not mean that they come first in priority or precedence in the event of competing or conflicting template rules, as discussed in Section 7.2.2. In fact, imported top-level elements are automatically considered last in priority to any top-level elements of the calling stylesheet. Imported top-level elements are also prioritized below any top-level elements included with <xsl:include>.

The top-level elements referenced by <xsl:import> are placed first in the calling XSLT stylesheet. When an XSLT processor operates on an XSLT stylesheet, the order of procedure is as follows.

  1. The XSLT stylesheet is parsed and checked for whether it is a well-formed XML data instance.

  2. Any external stylesheets referenced by <xsl:import> are accessed and their corresponding top-level elements are imported, provided the imported XSLT stylesheet itself is a well-formed XML data instance.

  3. Any top-level elements of external stylesheets referenced by <xsl:include> are included.

  4. This complete set of top-level elements is checked for conflicts and resolved according to the conflict resolution model presented in Section 7.2.2.

The imported top-level elements retain their base URI, namespace declarations, version, and extension-element-prefix and exclude-result-prefix attribute characteristics declared in the <xsl:stylesheet> or <xsl:transform> document element of their home XSLT stylesheet.

Again, if any elements of the imported set of top-level elements are themselves imported elements, they are treated as though referenced by an <xsl:import> element in the original importing XSLT stylesheet.

7.1.3 Comparing the <xsl:import> and <xsl:include> Top-Level Elements

The comparison between <xsl:import> and <xsl:include> is primarily based on the matter of conflict resolution. The simplest summary of their difference is that top-level elements brought into an XSLT stylesheet using the <xsl:import> element have lower precedence than the importing stylesheet's top-level elements or any top-level elements included with the use of <xsl:include>.

Remember that <xsl:include> effectively inserts additional top-level elements into the stylesheet in which it is invoked. The href attribute of <xsl:include> directs the XSLT processor to go to the URI given as its value, and from the stylesheet at that URI, the top-level elements are taken and put in place of in other words, at the same point in the including XSLT stylesheet the <xsl:include> element. The <xsl:import> element does this also, but with two distinctions. First, the <xsl:import> element comes first in document order in the XSLT stylesheet in which it is invoked. Therefore, the top-level elements from the XSLT stylesheet being imported come first. Second, the <xsl:import> top-level elements are not ranked above any top-level elements of the importing stylesheet.

The top-level elements brought into an XSLT stylesheet using <xsl:import> and <xsl:include> are the same in that they both retain the base URI, relative URIs, namespace declarations, and so forth of the included or imported top-level elements. In other words, the top-level elements combined into any XSLT stylesheet always retain all of their home stylesheet's the stylesheet from which they were either included or imported characteristics. As noted, the top-level elements referenced by way of <xsl:import>, when <xsl:import> is part of the elements included with <xsl:include>, are treated differently.

The basic thing to remember is that all <xsl:import> elements are resolved and placed at the front of the importing stylesheet before any further processing of additional elements is done.

The best way to explain this set of contingencies for conflict resolution and general import, and include procedures, is with a simplified example.

Consider that we have a primary XSLT stylesheet, called primary.xsl, and three referenced stylesheets, as shown in Example 7-3. The additional stylesheets are located in the same directory as primary.xsl to simplify their reference.

Example 7-3 Using imported and included stylesheets.
PRIMARY STYLESHEET: <?xml version="1.0"?> <!-- Primary Stylesheet primary.xsl --> <xsl:stylesheet       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"       version="1.0"> <xsl:import href="imported.xsl" /> <xsl:template match="/" priority="1">       <p>I'm the content of the original       template in primary.xsl.</p> </xsl:template> <xsl:include href="included.xsl" /> </xsl:stylesheet> IMPORTED STYLESHEET: <?xml version="1.0"?> <!-- Imported Stylesheet imported.xsl --> <xsl:stylesheet       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"       version="1.0"> <xsl:template match="/">       <p>I'm the content of imported.xsl. </p> </xsl:template> </xsl:stylesheet> NCLUDED STYLESHEET: <?xml version="1.0"?> <!-- Included Stylesheet included.xsl --> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:import href="import2.xsl" /> <xsl:template match="/">       <p>I'm the content of included.xsl.</p> </xsl:template> </xsl:stylesheet> 2nd IMPORTED STYLESHEET: <?xml version="1.0"?> <!-- 2nd Imported Stylesheet import2.xsl --> <xsl:stylesheet       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"       version="1.0"> <xsl:template match="/" priority="2">       <p>I'm the content of import2.xsl.</p> </xsl:template> </xsl:stylesheet> 

In the primary stylesheet above, we declared a priority value of 1 for the template. Each of the additional three XSLT stylesheets is referenced directly or indirectly by the primary.xsl stylesheet. The imported.xsl and included.xsl stylesheets are referenced directly in the primary.xsl stylesheet, but their templates do not have a priority set. The second imported stylesheet, import2.xsl, is referenced in included.xsl, and contains a template with a priority of 2.

Now, we will look at what happens to primary.xsl when all the imports and includes are resolved. Example 7-4 gives all the resulting contents, the imported and included top-level elements of primary.xsl to which the conflict resolution model must be applied. It is important to remember that the following is not meant to indicate that primary.xsl itself has changed in any way, but that once resolved, the <xsl:import> and <xsl:include> top-level elements have been "replaced" by the top-level elements of the stylesheets to which their href attributes referred. Therefore, we have put those referenced top-level elements that are being included and imported in place of the <xsl:import> and <xsl:include> elements that referenced them. We've also added comments that would not normally result from this process, but that help orient you to the origin of the material. Note that Example 7-4 is for demonstration purposes only to demonstrate how primary.xsl "looks" to the XSLT processor after imports and includes are done.

Example 7-4 The parsed primary.xsl stylesheet.
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"                 version="1.0"> <!-- The top-level elements from the imported.xsl XSLT stylesheet come first because the <xsl:import> element comes first itself. Therefore, from the perspective of the XSLT processor, this template rule, the only top-level element imported.xsl, has effectively "replaced" the <xsl:import> element which references it. --> <xsl:template match="/"><p>I'm the content of imported.xsl. </p> </xsl:template> <!-- This is the import2.xsl file, which was referenced in the included.xsl file. It comes at the beginning in document order because imported top-level elements from included files are treated as if they were referenced by an <xsl:import> element in the original including stylesheet. In other words, in this case, the contents of import2.xsl, referenced by included.xsl, are presented as though primary.xsl itself contained the <xsl:import> element used in included.xsl. The other top-level elements of included.xsl come below in the same document order of primary.xsl, in which the <xsl:include> was declared.  -->       <xsl:template match="/" priority="2">             <p>I'm the content of import2.xsl.</p>       </xsl:template> <!-- This is the original template rule of primary.xsl --> <xsl:template match="/" priority="1">       <p>I'm the content of the only template in primary.xsl.</p> </xsl:template> <!-- This is the top-level element from included.xsl, which was included by means of the <xsl:include> element in primary.xsl, last in document order. One of its top-level elements, this template rule, is included here in place of the <xsl:include> element that referenced it. The other top-level element, which referenced the import2.xsl stylesheet that was also part of included.xsl, was moved up in document order as though it was an <xsl:import> that was part of primary.xsl. --> <xsl:template match="/">       <p>I'm the content of included.xsl. </p> </xsl:template> </xsl:stylesheet> 

Most of the criteria for determining which template rules are placed where in the resulting pseudo-stylesheet above were explained in the intervening comment sections.

Regarding the matter of conflict resolution, notice that in each case, the <xsl:template> element's match attribute is the same, matching the root or document root with / as an abbreviation. There are therefore four conflicting template rules. This can be simply resolved by the criteria mentioned in Section 7.2.2. In the case of both the imported.xsl template rule and the import2.xsl template rule, they are automatically removed from contention for top priority by virtue of being imported top-level elements. If there are no priority attributes defined, the last template rule in the stylesheet (after all includes and imports have been resolved) is selected. This "order rule" of template selection can be overridden using the <xsl:apply-imports> instruction element, discussed in Section 7.1.4, by effectively reinserting the imported template at that location.

Any imported top-level element that conflicts with another non-imported top-level element will always lose out. This is true even when the template has a priority value higher than any other template in the stylesheet, as in our example, where import2.xsl has a template with a declared priority of 2. Again, the fact that the template rule from import2.xsl is imported (by virtue of being an import into the included.xsl file) obviates any stated priority with the priority attribute. Also, using <xsl:apply-imports>, discussed in the next section, does not change this implicit priority. An imported template with a higher priority attribute value cannot override any conflicting non-imported template rule. Internal templates will always have priority over external templates imported or included regardless of the priority given to the imported or included templates.

This leaves the original template rules from primary.xsl and included.xsl as "contenders" for priority among the four templates. In the case of the declaration of priority, even if the number is 1 or, for that matter, 1000 a declared priority will take precedence over a template with no priority attribute. Therefore the envelope, please the one template of all four that will be invoked is the content of the primary.xsl, which stipulates a priority attribute.

Note

Some parsers may not support more than two nested levels of included or imported files. For example, in the previous example, XT returns a different value when included.xsl contains an imported (import2.xsl) stylesheet.

7.1.4 The <xsl:apply-imports> Instruction Element

The <xsl:apply-imports> instruction element is used to effectively "requery" imported templates to find one that matches the current template rule's match. It allows a nesting of another template inside the calling template.

The <xsl:apply-imports> element has no attributes and is an empty element, as shown in the following element model definition. It can only be used inside a template, and is categorized as an instruction element.

<!-- Category: instruction --> <xsl:apply-imports /> 

The <xsl:apply-imports> element searches for an imported template rule with the same match criteria as the <xsl:template> element that calls it. For example, if a template rule is matching on "thoroughfare," <xsl:apply-imports> in that template rule will search for an imported template with a match value of "thoroughfare," as shown in Example 7-5.

The main stylesheet is doing the basic formatting for the lists, and the imported templates add titles for each thoroughfare and boulevard. We add an <xsl:import> element to the main stylesheet to import title.xsl and an <xsl:apply-imports> in the thoroughfare and boulevard template rules to use the contents of the imported templates.

The <xsl:apply-imports> effectively takes the content of the template rule in the imported stylesheet and uses it at the point it is called. The imported template does not affect the contents of the original template rule. They are both processed in order.

If there are several imported template rules that match the same criteria, the processor uses the same priority selection rules as a normal stylesheet, except that only the imported templates are checked.

Example 7-5 The using <xsl:apply-imports> to call an imported template.
MAIN STYLESHEET: <?xml version="1.0"?> <xsl:stylesheet       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"       version="1.0"> <xsl:import href="title.xsl" /> <xsl:template match="/">       <html>       <body>              <xsl:apply-templates/>       </body>       </html> </xsl:template> <xsl:template match="thoroughfare">              <xsl:apply-imports/>       <ul>              <xsl:apply-templates/>       </ul> </xsl:template> <xsl:template match="boulevard">              <xsl:apply-imports/>       <ul>              <xsl:apply-templates/>       </ul> </xsl:template> <xsl:template match="sidestreet | block">       <li>              <xsl:apply-templates/>       </li> </xsl:template> </xsl:stylesheet> IMPORTED STYLESHEET: <?xml version="1.0"?> <!-- imported stylesheet title.xsl --> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="thoroughfare">       <center>              <h1>Listing for <xsl:value-of select="@name | text()"/></h1>       </center> </xsl:template> <xsl:template match="boulevard">       <center>              <h1>Listing for the Boulevard</h1>       </center> </xsl:template> </xsl:stylesheet> OUTPUT: <html> <body> <center> <h1>Listing for Governor Drive</h1> </center> <ul>Governor Drive</ul> <center> <h1>Listing for Whitesburg Drive</h1> </center> <ul> <li>Bob Wallace Avenue</li> <li>Woodridge Street</li> </ul> <center> <h1>Listing for Bankhead</h1> </center> <ul> <li>Tollgate Road</li> <li>Oak Drive</li> </ul> <center> <h1>Listing for the Boulevard</h1> </center> <ul> <li>Panorama Street</li> <li>Highland Plaza</li> <li>Hutchens Avenue</li> <li>Wildwood Drive</li> <li>Old Chimney Road</li> <li>Carrol Circle</li> </ul> </body> </html> 

The <xsl:apply-imports> element is not a recursive rule like <xsl:apply-templates>, which looks for the children of the current element. However, if the included template contains an <xsl:apply-templates> element, the children will be processed at that point.

7.2 Template Rule Processing and Priorities

In this section, we will review the concepts of processing template rules and the procedures for resolving conflicts.

Almost every one of the priorities for resolving conflicts discussed in the following sections fall along the general lines that imported elements always have the lowest priority. Any processing or template priority resolution, however, is contingent upon the concept of the current template rule.

7.2.1 The Current Template Rule

The current template rule is always that rule which is being instantiated at any given point in the processing of an XSLT stylesheet. A given template rule becomes the current template rule once its match pattern has been successfully matched in the input XML data instance. The template rule is not the current template rule while the matching evaluation is occurring, but becomes so immediately upon a successful match and subsequent instantiation of the template it contains.

7.2.2 Conflict Resolution for Template Rules

The use of <xsl:import> and <xsl:include> elements raises additional considerations for the overall processing model of XSLT stylesheets. Specifically, it is quite possible that there can be competing or conflicting template rules. In other words, two or more <xsl:template> elements might match on the same node-set, for example. While it is possible for duplicate template rules to be defined in one stylesheet, it is much more likely that there will be duplicates when stylesheets are included or imported. The XSLT processor selects the appropriate template rule to use at any given time during the instantiation of the stylesheet, based on specific precedence and priority rules. The default selection criteria is based on the order rule of precedence.

7.2.2.1 The Order Rule of Precedence

There is a general procedure, or default processing model, for resolving conflicts or competing components in XML, which applies to precedence. For example, when defining entities in a DTD or document instance, if you define the same entity more than once, the last in document order as processed is given precedence. The same applies for template rules when no other factors affecting precedence are present.

When this happens, the same standard principle of "order" for resolving such conflicts (which is somewhat like the Biblical notion that the last shall be first) is used. In other words, the default processing model will always assign highest precedence to the last of any given set of equivalent or competing template rules. Order is used as the default precedence or conflict resolution when no other specific factors are identified to establish priority.

This basic "last shall be first" resolution rule is subject to several mediating provisions. As noted in Section 3.1.3.3, <xsl:template> elements can use the priority attribute to explicitly stipulate a precedence for resolution. If a priority is not specified, or priority is declared with an empty value, the precedence of template rules is selected using the "order rule" for precedence, according to the order they appear in the stylesheet.

When a match attribute on a template rule contains a union indicator (|) to effectively select more than one node-set, the template rule is treated as two separate rules, one for each choice in the order they occur. Once the two separate rules have been "split" in the processor's view, the same template selection rules apply.

7.2.2.2 Import Precedence of Template Rules

When imported templates are involved, the XSLT specification refers to this as the import precedence of a template. Templates are selected based on the order in which they were imported into the calling stylesheet. If the conflicting template comes before a template in the stylesheet, it has a lower import precedence, because imported templates are always first in the stylesheet. It may be helpful to remember that the last template rule in the document has the highest precedence. Using the example from the XSLT specification, Section 2.6.2:

  • stylesheet A imports stylesheets B and C in that order;

  • stylesheet B imports stylesheet D;

  • stylesheet C imports stylesheet E.

Then the order of import precedence (lowest first) is D, B, E, C, A. It is easier to imagine the order of import precedence with a diagram showing the implicit nested priority given to each as in Figure 7-1.

Figure 7-1. Model of import precedence among five stylesheets.

graphics/07fig01.gif

In this case, using <xsl:apply-templates select="block"> would automatically match the <xsl:template> rule 5 in stylesheet A, because it is the last template rule in the stylesheet.

Import precedence is lowest when the number is low and highest when the number is high, so in this example, 1 is lowest, which is the template rule in stylesheet D, and 5 is highest, which is the template rule from stylesheet A.

7.2.2.3 Priority of Template Rules

The priority attribute of the <xsl:template> element provides a means for an explicit order of selection to be used on template rules. Again, the higher numbers take higher priority.

Negative numbers are treated just like normal real negative numbers on a number scale; the higher the number, the lower the priority. In other words, -5 is lower than -2, so in a conflict, the template rule with a priority of -2 would get selected over the same template rule with a priority of -5.

Any <xsl:include> elements are resolved before the conflict resolution starts, much like resolving entities before parsing. The resulting template rule is treated as if it was originally written in the stylesheet, and not "included." Once <xsl:include> elements have been resolved, the conflict resolution process begins with these rules:

  1. If any conflicting rules result from an <xsl:import>, they are removed from consideration because they appear first in the fully resolved stylesheet.

  2. If a numerical priority has been stipulated with the priority attribute, the template rules are selected based on their priority value.

  3. If no priority has been stipulated, there is a default priority that is determined based on the nature of the pattern, which is the value of the <xsl:template> element's match attribute. Basically, the more specific the pattern, the higher the priority.

    If there are range of alternatives separated by |, then these are treated like individual rules. For example, <xsl:template match="block | sidestreet"> is treated as two separate template rules:

    <xsl:template match="block"> <xsl:template match="sidestreet"> 

    Priority is assigned to template rules that do not have explicit priority values assigned as follows:

    1. If the pattern is either namespaced or is a processing-instruction, and has an axis of either child or attribute, it is considered to have priority value of 0.

    2. If it is non-namespaced, or an NCName, and has an axis of either child or attribute, it has a slightly lower priority value of -0.25.

    3. If it just a node test, preceded by a child or attribute axis, then it is still lower with a value of -0.5.

    4. In any other case, the default priority is 0.5.

Many of these concepts are rarely necessary to consciously consider when writing a stylesheet, though they are worth referring to in debugging the unexpected results from one. The default priorities are already at work in any template rule, and so you need not memorize or be actively aware of them in order to construct and work with XSLT stylesheets. However, it is sometimes necessary to override the precedence and priorities of a template.

7.2.3 Overriding Import Template Rule Precedence and Priorities

When writing an XSLT stylesheet, you have two options of providing for anticipated or possible conflicts when you know in advance how you want them to be resolved. The first is by using the priority attribute on the <xsl:template> element. The second is by forcing a template to be selected at a certain location in a stylesheet, which entails the use of one of two XSLT instruction elements, either <xsl:apply-imports> or <xsl:call-template>. These elements are used within the context of an <xsl:template> to call and use the content of another <xsl:template> element. These two methods are discussed in the following sections.

7.2.3.1 Establishing Priority with the priority Attribute in <xsl:template>

In Chapter 3, we introduced the priority attribute of the <xsl:template> top-level element. In short, it is an optional attribute whose value can be a number, or an expression that resolves to a number, establishing the relative priority among two or more otherwise conflicting <xsl:template> elements.

Using priority is a simple matter of knowing how many possible conflicts one has and numbering them according to the preferred resolution for order of precedence, as shown in Example 7-6.

Example 7-6 Resolving conflicts with the priority attribute in a template.
<xsl:template match="/" priority="1">       <!-- do some stuff --> </xsl:template> <xsl:template match="/" priority="2">       <!-- do different stuff --> </xsl:template> 

In this example, the priority attribute or even the need for two different template rules seems sort of pointless. As it is written, the template rule with a priority of 2 always wins out, simply because it comes last in the document. However, the processor is not using the "order rule" in this case because the <xsl:template> elements have a priority attribute, so if the order of the template rules was reversed, the priority 2 template would still be used instead of the one with a priority of 1.

In all cases with template rules that are not imported, if the priority attribute is declared, it will determine which of the conflicting template rules is invoked. The priority attribute value for an imported top-level element, however, cannot under any circumstances elevate the relative priority of an imported element over a non-imported element. However, top-level elements brought into a stylesheet with <xsl:include> are not considered to be imported, so their relative priority attribute values, if given, do apply.

7.2.3.2 Overriding Import Priority with <xsl:apply-imports>

The <xsl:apply-imports> instruction element, discussed in Section 7.1.4, works within the context of the current template rule in which it is called. In effect, it references <xsl:template> elements imported with a declaration of <xsl:import> and applies the content of the imported template to the current template rule at the point where it is referenced. Where imported elements are otherwise lowest on the possible priority list for conflicting elements, they are "redeemed" when <xsl:apply-imports> is used. The selection of the template that is used still follows the rules for priority, but the selection is limited to only those templates that were imported. This does not affect the original priority that was used to select the current template rule. Because <xsl:apply-imports> can only be used inside a template rule, the original template rule must be matched and instantiated, using the original priority rules, prior to processing the imported rule.

Using the <xsl:apply-imports> element does not "remove" the other template rules. It is used to allow nested processing of template rules that would otherwise never be matched because they were imported.

7.2.3.3 Overriding Import Priority with <xsl:call-template>

The <xsl:call-template> element, covered in Chapter 3, is used to call template elements that have been specifically named. The <xsl:call-template> element is only used within the context of an <xsl:template> element and is used to force the use of a named template at the point where it is called. When using the <xsl:call-template> element, it is necessary to have declared a template by name and use that name for calling it.

One of the most interesting things about <xsl:call-template> is that it can be used to invoke imported templates by name provided they have been given a name with the name attribute such that their otherwise lowly position in the hierarchy is obviated. Again, this is largely the same effect as the <xsl:apply-imports>, but the selection of the template rule is specifically targeted by using a name, whether the named template is declared in the home stylesheet or in an external stylesheet. While the <xsl:apply-imports> element only selects the imported template with the highest priority, <xsl:call-template> selects a specific template, ignoring all priority and import rules.

For example, working with the files from Example 7-5, we could add a name to the imported template, title.xsl, as shown in Example 7-7.

Example 7-7 Modified title.xsl with a named template.
<?xml version="1.0"?> <!-- imported stylesheet title.xsl --> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="thoroughfare" name="called-template">       <center>             <h1>Listing for <xsl:value-of select="@name | text()"/></h1>       </center> </xsl:template> <xsl:template match="boulevard">       <center>             <h1>Listing for the Boulevard</h1>       </center> </xsl:template> </xsl:stylesheet> 

We could then use <xsl:call-template> in the main stylesheet to elevate that part of title.xsl so that the precedence of the imported elements is ignored. The named template is called using the name attribute of the <xsl:call-template> element, as shown below.

<xsl:template match="thoroughfare">             <xsl:call-template name="called-template"/>       <ul>             <xsl:apply-templates/>       </ul> </xsl:template> 

Once again, all the included and imported stylesheets will be resolved, and since the named template called-template is part of the imported elements from title.xsl, it can be invoked by name. The match attribute on the called template is ignored, and the content of the template is used within the context of the template calling the called-template. The same rules of precedence apply to the calling template when using the <xsl:call-template> element, and the called template's content is used, regardless of its original precedence or priority. The other template rules from the imported elements are not addressed directly, so they keep their order in the priority rules.

CONTENTS


XSLT and XPATH(c) A Guide to XML Transformations
XSLT and XPATH: A Guide to XML Transformations
ISBN: 0130404462
EAN: 2147483647
Year: 2005
Pages: 18

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net