xsl:template匹配模式中的变量

8

给定

一个带有全局变量的XSLT样式表:

<xsl:variable name="lang" select="/response/str[@name='lang']"/>

问题

为什么在 xsl:template 匹配模式中使用谓词中的变量是不正确的,但在 xsl:apply-templates 选择模式中使用是可接受的?

<!-- throws compilation error, at least in libxslt --> 
<xsl:template match="list[@name='item_list'][$lang]"/>

<!-- works as expected --> 
<xsl:template match="list[@name='item_list'][/response/str[@name='lang']]"/>

<!-- works as expected --> 
<xsl:template match="response">
    <xsl:apply-templates select="list[@name='item_list'][$lang]">
</xsl:template>

我不确定这是否是限制,但您确定您的$lang包含字符串值(或数字),而不是某些节点集吗? - YuS
@yuri,它确实包含一个节点集,但我不明白为什么在这种情况下不允许使用节点集。 - newtover
1
我不能告诉你为什么在XSLT 1.0中指定了限制的详细信息,但我可以告诉你,在XSLT 2.0中已经消除了这个限制,因此你可能想考虑转移到该语言的那个版本以及其实现之一,例如Saxon 9或AltovaXML。 - Martin Honnen
@martin-honnen,我使用Python中的libxslt,并且很久以前在php中也看到了相同的限制。这从未阻碍过我的工作,但现在我决定找出原因。如果是Java或.Net,我肯定会使用Saxon,但XSLT 1.0实际上已经满足了我所有的需求。 - newtover
可能是重复的问题:xsl:如何在“match”内部使用参数? - l0b0
1个回答

11

XSLT 1.0不允许在匹配表达式中使用变量。

根据XSLT 1.0规范:定义模板规则

包含VariableReference的匹配属性的值是一个错误。

XSLT 2.0允许在匹配表达式中使用变量。

根据XSLT 2.0规范:Pattern Syntax

模式可以以id FO或key函数调用开头,只要待匹配的值以字面量或变量或参数引用的形式提供,并且键名(在键函数的情况下)以字符串字面量的形式提供。这些模式将永远不会匹配不是文档节点的树中的节点。


谢谢!在提问之前,我确实看了规范的那一部分,但不知怎么错过了你引用的那句话。我需要睡个好觉! - newtover
1
@newtover:另外,您还问为什么在xsl:apply-templates选择模式中变量引用“是可以接受的”。答案是,在xsl:apply-templates中的select不是模式,而是XPath表达式。模式看起来很像XPath表达式,但它们并不相同。这个变量引用限制是其中一个区别(在XSLT 1.0中)。 - LarsH
Mads,我认为你关于变量何时允许在匹配表达式中的说法并不完全准确,基于我对规范的阅读。我认为你可以简单地说“在XSLT 2.0中,变量允许出现在匹配表达式中”,即使它们引用文档节点。只是包含key()和id()函数调用的模式永远不会匹配根不是文档节点的树中的节点...但这并不限制模式中变量的值可以是什么。 - LarsH
感谢您进行编辑。我还想说,我认为引用的段落并没有告诉我们任何关于在匹配模式中允许使用变量的信息(除了不能使用变量作为键名之外)。它实际上只是关于模式中id()key()函数调用的限制。 - LarsH
那么问题就出现了,规范的哪一部分告诉我们在匹配模式中允许使用变量?我认为答案是模式的语法,包括“PredicateList”的产生式,引用了某些符号,这些符号在其扩展中的某个地方被指定为允许使用“VarRef”。 - LarsH
看起来 PredicateList 和 IdKeyPattern 涵盖了允许 VarRef 的模式语法中的所有符号。这意味着在谓词和 id/key 函数调用之外的匹配模式中不允许使用变量。我不知道这一点。(我想不出为什么你会想以其他方式使用变量,例如在匹配模式中“裸露”使用变量。) - LarsH

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接