XSLT Template Default Priority Calculation
When an XSLT processor encounters multiple matching
<xsl:template> rules for a single XML node, it relies
on template priority to resolve conflicts. If a template does not
contain an explicit priority attribute, the processor
automatically calculates a default priority based on the specificity of
the pattern in the match attribute. This article outlines
the exact scoring algorithm defined by the W3C XSLT specification to
compute these default priorities.
The Default Priority Scoring Rules
The default priority calculation evaluates the syntax of the match pattern and assigns a numeric value ranging from -0.5 to +0.5. The algorithm categorizes match patterns into four distinct levels of specificity:
1. Priority +0.5: Highly Specific Patterns
A pattern is assigned a default priority of +0.5 if
it goes beyond a simple node test. This includes patterns that contain:
* Predicates (e.g., para[@type='warning'] or
item[1]) * Child, descendant, or parent path steps (e.g.,
chapter/section, div//p, or
list/item) * Functions used as match patterns, such as
key() or id() (e.g., id('main')
or key('item-by-id', '123'))
2. Priority 0.0: Specific Name Tests
A pattern receives a default priority of 0.0 if it
matches a specific qualified name (QName) or a specific processing
instruction target: * Specific element names (e.g., title,
xsl:template) * Specific attribute names (e.g.,
@id, @class) * Processing instruction tests
with a specific literal argument (e.g.,
processing-instruction('xml-stylesheet'))
3. Priority -0.25: Namespace Wildcards
A pattern is assigned a default priority of -0.25 if
it tests for nodes within a specific namespace or with a specific local
name using wildcards: * Prefix wildcards (e.g., ns:* or
@ns:*) * Local-name wildcards (e.g.,
*:elementName in XSLT 2.0 and later)
4. Priority -0.5: Generic Node Tests and Wildcards
A pattern receives the lowest default priority of
-0.5 if it is a general wildcard or basic node-type
test: * Principal node wildcards (e.g., * or
@*) * Generic node-type tests (e.g., node(),
text(), comment(), or argument-less
processing-instruction())
Handling Union Patterns
(|)
If a template match attribute contains a union operator (e.g.,
match="para | @title"), the pattern is treated as a set of
individual template rules. The priority is computed independently for
each alternative in the union rather than for the expression as a
whole.
Conflict Resolution with Equal Priorities
If two or more matching templates share the exact same calculated or explicit priority, the XSLT processor resolves the conflict using import precedence: 1. Templates defined in importing stylesheets take precedence over those in imported stylesheets. 2. If the conflicting templates have the same import precedence, the processor must choose the template that appears last in the stylesheet, or it may signal an error depending on the XSLT processor configuration.