XSL template precedence - xslt

I have 2 Templates
<template match="vehicle_details[preceding-sibling::vehicle_type = '4x4']/*">
...
</xsl:template>
<xsl:template match="vehicle_details[descendant::color = 'red']/*" >
...
</xsl:template>
My question is: which template will take precedence on transformation. And can someone give me an overview/resources about XSL template precedence?
Thanks in advance!

The full resolution process is described in section 5.5 of the XSLT spec.
In general, the following rules apply in order (e.g. a template eliminated from consideration due to lower import precedence is eliminated permanently, regardless of its priority):
Imported templates have lower precedence than templates in the primary stylesheet
Templates with a higher value in their priority attribute have higher precedence
Templates without a priority attribute are assigned a default priority. Templates with more specific patterns take precedence.
It's an error if the previous three steps leave more than one template in consideration, but XSLT processors can recover by defaulting to the last one in the file.
In your specific case both templates have the same priority, so #4 above applies. To demonstrate:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match=
"vehicle_details[preceding-sibling::vehicle_type = '4x4']/*">
template1
</xsl:template>
<xsl:template match="vehicle_details[descendant::color = 'red']/*">
template2
</xsl:template>
</xsl:stylesheet>
Applied to this input (both templates match):
<root>
<vehicle_type>4x4</vehicle_type>
<vehicle_details>
<color>red</color>
</vehicle_details>
</root>
Output:
template2
But if we swap the order of the templates:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="vehicle_details[descendant::color = 'red']/*">
template2
</xsl:template>
<xsl:template match=
"vehicle_details[preceding-sibling::vehicle_type = '4x4']/*">
template1
</xsl:template>
</xsl:stylesheet>
Then the output is:
template1

Related

XSLT templates' ambiguity clarification

When ran the following input XML
<root>
<value>false</value>
<value>true</value>
</root>
against the following XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="value">
<true_value/>
</xsl:template>
<xsl:template match="value[. = 'false']">
<false_value/>
</xsl:template>
</xsl:stylesheet>
I get value element with 'false' as its content changed to false_value.. and all other value elements are turned into true_value.
Output:
<?xml version="1.0" encoding="utf-8"?>
<root>
<false_value/>
<true_value/>
</root>
But only when I change the template match to root/value do I get ambiguous template warning.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root/value">
<true_value/>
</xsl:template>
<xsl:template match="root/value[. = 'false']">
<false_value/>
</xsl:template>
</xsl:stylesheet>
Please help me by explaining what difference does addition of root to the xpath in xsl:template's #match makes that I get this warning.(Ambiguous rule match for /root[1]/value[1])
Your result is due to implicit template priorities. You can explicitly specify a priority on any template:
<xsl:template match="foo" priority="2"/>
But in most cases, you do not state explicitly what priority you would like a template to adopt - and that's where the default priorities step in. If there is conflict between templates, that is, if an input node matches several templates, XSLT defines a conflict resolution procedure that makes use of the default priorities.
The two templates that cause the processor to issue a warning:
<xsl:template match="root/value">
and
<xsl:template match="root/value[. = 'false']">
have the same default priority (0.5). You would think that the match pattern match="root/value[. = 'false']" is more specific than match="root/value", but as far as the specification is concerned, it is not - they have exactly the same priority.
And that is why an ambiguous rule match is reported. An ambiguous rule match is a situation where the conflict cannot be resolved with either the explicit or implicit priorities. As a last resort, the last template is chosen.
To complete this thought experiment, change the order of templates to
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="root/value[. = 'false']">
<false_value/>
</xsl:template>
<xsl:template match="root/value">
<true_value/>
</xsl:template>
</xsl:stylesheet>
And the result will be (see it online here):
<?xml version="1.0" encoding="utf-8"?>
<root>
<true_value/>
<true_value/>
</root>
As you can see, for both value elements, the last template is chosen.
Why, then, does adding root/ to a template match result in a warning about template ambiguity?
The specific change you make is from
<xsl:template match="value">
to
<xsl:template match="root/value">
This changes the default priority (as discussed above) of the template. The default priority of value is 0, the default priority of root/value is 0.5. Only in the second case a conflict will arise, because the default priority of the other template is also 0.5.
Adding root/ to the second template:
<xsl:template match="root/value[. = 'false']">
does not change anything, the default priority remains 0.5.
See the relevant part of the XSLT specification. Caveat: the default priorities there are not exactly easy to read.
All priorities:
<xsl:template match="value"> 0
<xsl:template match="value[. = 'false']"> 0.5
<xsl:template match="root/value"> 0.5
<xsl:template match="root/value[. = 'false']"> 0.5
In general the default priorities are meant to indicate the specificity of the match pattern in the template rule. The match pattern "value" is less specific than "root/value" which only matches a value element with a root parent hence root/value has a higher default priority.
That default priority (0.5) happens to be the same as that of a match pattern that features a predicate (note that root/value can also be written as value[parent::root]) and that caused your template conflict.
You are also vulnerable to template conflict on your first template pattern which is the identity template which (for example) will conflict with a template that matched *. Note that when such conflicts are found it is permissible for an XSLT processor to fail rather than try to choose based on the position of the respective templates
If the identity transform is imported from it's stylesheet, needless duplication is eliminated and conflicts are mitigated because templates from imported stylesheets have a lower precedence than templates in the importing stylesheet.

XPath filter not working on XSL

I have the following XML
<?xml version="1.0"?>
<people><human><sex>male</sex><naxme>Juanito</naxme>
</human>
<human><sex>female</sex><naxme>Petra</naxme></human>
<human><sex>male</sex><naxme>Anaximandro</naxme></human>
</people>
and this XSL
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8" indent="no"/>
<xsl:template match="/people/human[sex='male']">
<xsl:value-of select="naxme"/>
</xsl:template>
</xsl:stylesheet>
I'm expecting it to filter out the female, and it kind of works but I get odd values for the non-matching nodes:
Juanito
femalePetra
Anaximandro
I'm expecting the same output as with
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8" indent="no"/>
<xsl:template match="/people/human">
<xsl:if test = "sex='male'">
<xsl:value-of select="naxme"/>
</xsl:if> </xsl:template>
</xsl:stylesheet>
Thanks!
I'll expand on Daniels answer which covers a little of the why.
The reason you are getting two different outputs comes down to the built-in template rules, and how nodes and text are treated by default.
Summarising that link, if no other template exists, there are default templates that ensure every node - be it element, text, attribute, comment - will be encoutered, just to ensure that other nodes that do have rules can be processed correctly.
With this XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/people/human[sex='male']">
<xsl:value-of select="naxme"/>
</xsl:template>
</xsl:stylesheet>
you have an explicit rule that says:
If you find a node that matches the XPath /people/human[sex='male] do this template.
Along with the default rule:
Find all nodes, and then process all of their children. If it is text, just output the text.
This default rule is why your template is being processed, since you have no explicit rule for the root node - / - it any every child and grandchild node are processed using the default rules, unless another exists. As such, each node is traversed using the defaults, except for the nodes matching /people/human[sex='male]. The result of this is that when you have a node that is "female" the text is being spat out instead of ignored.
However, contrast this with:
<xsl:template match="/people/human">
<xsl:if test = "sex='male'">
<xsl:value-of select="naxme"/>
</xsl:if>
</xsl:template>
Where the rule becomes:
If you find a node that matches the XPath /people/human do this template.
It just so happens that in that template, you have an extra condition that says, if it is male, then process it in some way, with no other conditions, so if a "female" node is encountered it is now blank in the output.
Lastly, the reason why Daniels answer works but could easily break, is that it changes the rule for processing text. Instead of now copying all text as in the default rules, it outputs nothing (as per the empty template. However, if you had any other templates which used xsl:apply-templates to process text and were expecting text, they would also now output nothing.
It's probably because of XSLT's built-in template rules. Try adding this template:
<xsl:template match="text()"/>

XSLT apply-template with mode - Incorrect result with no matching mode

Here's a simple case.
Here's my XML:
<?xml version="1.0" encoding="utf-8" ?>
<dogs>
<dog type="Labrador">
<Name>Doggy</Name>
</dog>
<dog type="Batard">
<Name>Unknown</Name>
</dog>
</dogs>
This XML is used with two Xslt. This is the common one:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="text"/>
<xsl:template match="dogs">
<xsl:text>First template
</xsl:text>
<xsl:apply-templates select="." mode="othertemplate" />
</xsl:template>
</xsl:stylesheet>
This is the child one:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:include href="transform.xslt"/>
<xsl:template match="dogs" mode="othertemplate">
<xsl:text> Other template</xsl:text>
</xsl:template>
</xsl:stylesheet>
The child includes the common one (called transform.xslt).
When I execute the child, I get the expected result:
First template
Other template
When I execute the common one, I get this strange results:
First template
Doggy
Unknown
The common one applies a template with the mode "othertemplate". This mode is only included, some times, in the child xslt.
I want that, if there's no template with mode "othertemplate", then nothing should be outputted.
I don't want to include a template with mode "othertemplate" with empty body for all xslt files that does not have to use this template mode...
What should I do?
Thanks
Built-in Template Rules in XSLT
The element contents and the extra whitespace appear because of XSLT's built-in template rules, also known as default templates. These rules are applied when there is no other matching template. The built-in template rules are
<xsl:template match="*|/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()|#*">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="processing-instruction()|comment()"/>
Built-in template rules process root and element nodes recursively and copy text (and attribute values if attribute nodes are selected). The built-in template rule for processing instructions and comments is to do nothing. Namespace nodes are not processed by default. Note that <xsl:apply-templates/> is practically a shorthand for <xsl:apply-templates select="child::node()"/> so it will not select attribute or namespace nodes.
There is also a built-in template rule for every mode. These templates are like default templates for elements and root except they continue processing in the same mode.
<xsl:template match="*|/" mode="foobar">
<xsl:apply-templates mode="foobar"/>
</xsl:template>
Because your stylesheet doesn't have a template matching dogs with mode othertemplate this built-in template rule is applied which in this case results in processing all child nodes and eventually printing the text nodes. Indentation and line feeds between the source document's elements are also text nodes so they also get printed and cause the extra whitespace in the output.
Warning on non-terminating loops because of <xsl:apply-templates select="."/>
Typically apply-templates is used to process descendants. In your example code you selected the current node when calling apply-templates. This may result in non-terminating loop if the template itself is applied because of an apply-templates command inside it. Example below
<xsl:template match="foobar">
<!-- This is an infinite loop -->
<xsl:apply-templates select="."/>
</xsl:template>
By the way. On a general rule on combining stylesheets, think carefully which template you should run and which one you should import or include. (I have read that as a general practice, Michael Kay seems to recommend using <xsl:import> to import the general-case stylesheet into the special-case stylesheet, not the other way round.)
The built-in XSLT templates are defined and selected for every mode. So, the built-in template for text nodes is selected and (by definition) it outputs the text node.
To suppress this, you need to override thie built-in template for text nodes (also possibly for elements) in your desired mode with an empty template:
<xsl:template match="text()" mode="othertemplate"/>
Include the above in your imported stylesheet.

Why does XSLT output all text by default?

Hi I had performed a transformation which drops a tag if it is null.
I wanted to check whether my transformation is working fine, so instead of checking it manually, I wrote one more XSLT code which just checks the presence of that particular tag in the OUTPUT XML, if it is null, then the second XSLT should output a text "FOUND". (I don't actually need some XML kind of output but I am just using XSLT for searching.)
When I tried with this XSL code ::
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/SiebelMessage//SuppressCalendar[.!='']">
FOUND
</xsl:template>
</xsl:stylesheet>
It outputs all the TEXT DATA that is present in the XML file,
to avoid that, I had to write this code::
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/SiebelMessage//SuppressCalendar[.!='']">
FOUND
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
why did the former code outputs TEXT, why should I insist XSL to ignore all other text? is that the behavior of all XML parsers or only of my own (I am using msxml parser).
why did the former code outputs TEXT,
why should I insist XSL to ignore all
other text? is that the behavior of
all XML parsers or only of my own
You are discovering one of the most fundamental XSLT features as specified in the Specification: the built-in templates of XSLT.
From the Spec:
There is a built-in template rule to
allow recursive processing to continue
in the absence of a successful pattern
match by an explicit template rule in
the stylesheet. This template rule
applies to both element nodes and the
root node. The following shows the
equivalent of the built-in template
rule:
<xsl:template match="*|/">
<xsl:apply-templates/>
</xsl:template>
There is also a built-in template rule
for each mode, which allows recursive
processing to continue in the same
mode in the absence of a successful
pattern match by an explicit template
rule in the stylesheet. This template
rule applies to both element nodes and
the root node. The following shows the
equivalent of the built-in template
rule for mode m.
<xsl:template match="*|/" mode="m">
<xsl:apply-templates mode="m"/>
</xsl:template>
There is also a built-in template rule
for text and attribute nodes that
copies text through:
<xsl:template match="text()|#*">
<xsl:value-of select="."/>
</xsl:template>
The built-in template rule for
processing instructions and comments
is to do nothing.
<xsl:template match="processing-instruction()|comment()"/>
The built-in template rule for
namespace nodes is also to do nothing.
There is no pattern that can match a
namespace node; so, the built-in
template rule is the only template
rule that is applied for namespace
nodes.
The built-in template rules are
treated as if they were imported
implicitly before the stylesheet and
so have lower import precedence than
all other template rules. Thus, the
author can override a built-in
template rule by including an explicit
template rule.
So, the reported behavior is the result of the application of the built-in templates -- the 1st and 2nd of all three of them.
It is a good XSLT design pattern to override the built-in templates with your own that will issue an error message whenever called so that the programmer immediately knows his transformation is "leaking":
For example, if there is this XML document:
<a>
<b>
<c>Don't want to see this</c>
</b>
</a>
and it is processed with this transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="a|b">
<xsl:copy>
<xsl:attribute name="name">
<xsl:value-of select="name()"/>
</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
the result is:
<a name="a">
<b name="b">Don't want to see this</b>
</a>
and the programmer will be greatly confused how the unwanted text appeared.
However, just adding this catch-all template helps avoid any such confusion and catch errors immediately:
<xsl:template match="*">
<xsl:message terminate="no">
WARNING: Unmatched element: <xsl:value-of select="name()"/>
</xsl:message>
<xsl:apply-templates/>
</xsl:template>
Now, besides the confusing output the programmer gets a warning that explains the problem immediately:
WARNING: Unmatched element: c
Later Addition by Michael Kay for XSLT 3.0
In XSLT 3.0, rather than adding a catch-all template rule, you can specify the fallback behaviour on an xsl:mode declaration. For example, <xsl:mode on-no-match="shallow-skip"/> causes all nodes that are not matched (including text nodes) to be skipped, while <xsl:mode on-no-match="fail"/> treats a no-match as an error, and <xsl:mode warning-on-no-match="true"/> results in a warning.
There are several built in template rules in XSL, one of which is this:
<xsl:template match="text()|#*">
<xsl:value-of select="."/>
</xsl:template>
It outputs text.

Parameters not being passed into template when using the .Net transform classes

I am using the .Net XslCompiledTranform to run some simple XSLT (see below for a simplified example).
The example XSLT is meant to do simply show the value of the parameter that is passed in to the template. The output is what I expect it to be (i.e.
<result xmlns:p1="http://www.doesnotexist.com">
<valueOfParamA>valueA</valueOfParamA>
</result>
when I use Saxon 9.0, but when I use XslCompiledTransform (XslTransform) in .net I get
<result xmlns:p1="http://www.doesnotexist.com">
<valueOfParamA></valueOfParamA>
</result>
The problem is that that the parameter value of paramA is not being passed into the template when I use the .Net classes. I completely stumped as to why. when I step through in Visual Studio, the debugger says that the template will be called with paramA='valueA' but when execution switches to the template the value of paramA is blank.
Can anyone explain why this is happening? Is this a bug in the MS implementation or (more likely) am I doing something that is forbidden in XSLT?
Any help greatly appreciated.
This is the XSLT that I am using
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:extfn="http://exslt.org/common" exclude-result-prefixes="extfn" xmlns:p1="http://www.doesnotexist.com">
<!--
Replace msxml with
xmlns:extfn="http://exslt.org/common"
xmlns:extfn="urn:schemas-microsoft-com:xslt"
-->
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="resultTreeFragment">
<p1:foo>
</p1:foo>
</xsl:variable>
<xsl:variable name="nodeset" select="extfn:node-set($resultTreeFragment)"/>
<result>
<xsl:apply-templates select="$nodeset" mode="AParticularMode">
<xsl:with-param name="paramA" select="'valueA'"/>
</xsl:apply-templates>
</result>
</xsl:template>
<xsl:template match="p1:foo" mode="AParticularMode">
<xsl:param name="paramA"/>
<valueOfParamA>
<xsl:value-of select="$paramA"/>
</valueOfParamA>
</xsl:template>
</xsl:stylesheet>
There is nothing strange -- this is the expected behavior of any XSLT 1.0 -compliant processor.
Explanation:
The $nodeset variable defined as:
<xsl:variable name="nodeset" select="extfn:node-set($resultTreeFragment)"/>
in XSLT 1.0 contains a complete xml document -- a document node, denoted in XPath 1.0 by / .
Therefore,
<xsl:apply-templates select="$nodeset" mode="AParticularMode">
<xsl:with-param name="paramA" select="'valueA'"/>
</xsl:apply-templates>
Will aplly a template matching the tree (the document node /) in the specified mode, if such template exists. In your case no such template exists. Therefore the built-in XSLT 1.0 template for / is applied (which belongs to every mode).
The text of the built-in template can be found in the spec:
<xsl:template match="*|/">
<xsl:apply-templates/>
</xsl:template>
As per spec:
"There is also a built-in template rule for each mode, which allows recursive processing to continue in the same mode in the absence of a successful pattern match by an explicit template rule in the stylesheet. This template rule applies to both element nodes and the root node. The following shows the equivalent of the built-in template rule for mode m.
<xsl:template match="*|/" mode="m">
<xsl:apply-templates mode="m"/>
</xsl:template>
"
Of course, the built-in template doesn't know anything about your parameter $paramA and it doesn't pass it down to the applied templates.
Thus, finally, your template matching p1:foo" in mode="AParticularMode" is selected for processing. Nothing is passed as value for the parameter, so it has no value -- thus the <xsl:value-of> doesn't produce even a single character or node.
To correct this problem, simply add a template matching / and in mode "AParticularMode":
<xsl:template match="/" mode="AParticularMode">
<xsl:param name="paramA"/>
<xsl:apply-templates mode="AParticularMode">
<xsl:with-param name="paramA" select="$paramA"/>
</xsl:apply-templates>
</xsl:template>
and now you get the desired result.
In XSLT 2.0 (Saxon 9) you observe different behavior, because the built-in templates in XSLT 2.0 by definition retransmit all parameters with which they were applied -- see the XSLT 2.0 Spec :
"If the built-in rule was invoked with parameters, those parameters
are passed on in the implicit xsl:apply-templates instruction."
Answer for your question,
Why my first attempt failed?
As you are using node-set() comfortably in your code I guess you might be well aware of Result Tree Fragment. If not, then go through this link.
Well. By taking advantage of RTF[Result tree fragment] you are able to treat "foo" as a node.
The variable $nodeset has stored the tree-structure of the node, so that you can treat it's value as node-set, where as variable $nodeset is still a variable. If you want to apply-template then apply on, it's child nodes[precisely elements] appearing as it's value,
Instead of * you could have used,
<xsl:apply-templates select="$nodeset/p1:foo" mode="AParticularMode">
This is more precise,
Well after more experimenting I found that altering the apply-templates to
<xsl:apply-templates select="$nodeset/*" mode="AParticularMode">
<xsl:with-param name="paramA" select="'valueA'"/>
</xsl:apply-templates>
(note the select="$nodeset/*" instead of select="nodeset") made it work as I wanted it to in .Net and Saxon.
I would however still be grateful if someone can explain why my first attempt failed.