运行时,以下输入 XML
<root>
<value>false</value>
<value>true</value>
</root>
针对以下 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>
我得到value
带有"false"的元素,因为它的内容更改为 false_value
..,所有其他value
元素都变成了true_value
。输出:
<?xml version="1.0" encoding="utf-8"?>
<root>
<false_value/>
<true_value/>
</root>
但只有当我将模板匹配更改为root/value
时,我才会收到模棱两可的模板警告。
<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>
请帮助我解释在 xsl:template
的 @match
中向 xpath 添加root
有什么区别,使我收到此警告。( Ambiguous rule match for /root[1]/value[1]
)
您的结果是由于隐式模板优先级。您可以在任何模板上显式指定优先级:
<xsl:template match="foo" priority="2"/>
但在大多数情况下,您不会明确说明您希望模板采用的优先级 - 这就是默认优先级介入的地方。如果模板之间存在冲突,即输入节点与多个模板匹配,XSLT 将定义使用默认优先级的冲突解决过程。
导致处理器发出警告的两个模板:
<xsl:template match="root/value">
和
<xsl:template match="root/value[. = 'false']">
具有相同的默认优先级 (0.5)。您可能会认为匹配模式match="root/value[. = 'false']"
比match="root/value"
更具体,但就规范而言,事实并非如此 - 它们具有完全相同的优先级。
这就是报告模棱两可的规则匹配的原因。不明确的规则匹配是指无法使用显式或隐式优先级解决冲突的情况。作为最后的手段,选择最后一个模板。
要完成此思想实验,请将模板的顺序更改为
<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>
结果将是(在此处在线查看):
<?xml version="1.0" encoding="utf-8"?>
<root>
<true_value/>
<true_value/>
</root>
如您所见,对于两个value
元素,都选择了最后一个模板。
那么,为什么向模板匹配添加root/
会导致有关模板多义性的警告?
您所做的具体更改来自
<xsl:template match="value">
自
<xsl:template match="root/value">
这将更改模板的默认优先级(如上所述)。value
的默认优先级为 0,root/value
的默认优先级为 0.5。只有在第二种情况下才会发生冲突,因为另一个模板的默认优先级也是 0.5。
将root/
添加到第二个模板:
<xsl:template match="root/value[. = 'false']">
不更改任何内容,默认优先级仍为 0.5。
请参阅 XSLT 规范的相关部分。警告:那里的默认优先级并不容易阅读。
所有优先事项:
<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
通常,默认优先级旨在指示模板规则中匹配模式的特殊性。匹配模式"值"不如"根/值"具体,后者仅将值元素与根父元素匹配,因此根/值具有更高的默认优先级。
默认优先级 (0.5) 恰好与具有谓词的匹配模式相同(请注意,root/value 也可以写为 value[parent::root]),这导致了模板冲突。
您也容易受到第一个模板模式(例如)与匹配 * 的模板冲突的影响,该模板是标识模板,该模板将与 * 匹配的模板冲突。请注意,当发现此类冲突时,允许 XSLT 处理器失败,而不是尝试根据相应模板的位置进行选择
如果标识转换是从其样式表中导入的,则会消除不必要的重复并减少冲突,因为导入样式表中的模板的优先级低于导入样式表中的模板。