XSLT templates' ambiguity clarification

xpath, xslt, xslt-1.0, xslt-2.0

Solution

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

Problem

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]`)

Original source