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.


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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.28.181