我觉得我已经很好地掌握了XSLT,但以下内容让我觉得:
为什么不明确声明它的被调用模板无法访问xsl:param
?换句话说,如果我从模板A调用模板B:
样式表1
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/" name="A"><!--This template is named "A" for convenience only.-->
<xsl:param name="hello" select="hello "/>
<xsl:param name="world" select="world!"/>
<xsl:call-template name="B"/>
</xsl:template>
<xsl:template name="B">
<xsl:value-of select="concat($hello,$world)"/>
</xsl:template>
</xsl:stylesheet>
为什么模板B不会自动采用模板A的参数作为上下文的一部分?我的理由如下。
显然,调用模板不会以任何方式影响上下文:
评估选定的
<xsl:template>
时没有更改上下文:它使用与调用模板 1
现在,“上下文”在XSLT中实际意味着什么,或者更确切地说,是一个被认为是上下文的一部分的参数?形成背景的事物包括 2 :
xsl:variable
和xsl:param
)这让我相信以下样式表与我展示的第一个样式表相同:
样式表2
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/" name="A">
<xsl:param name="hello" select="hello "/>
<xsl:param name="world" select="world!"/>
<xsl:value-of select="concat($hello,$world)"/>
</xsl:template>
</xsl:stylesheet>
但是很明显,只有第二个是正确的,而第一个产生关于缺少变量声明的两个错误。如果模板调用不改变上下文并且参数被视为上下文的一部分,为什么必须在调用的模板中显式声明参数?
为清楚起见:
xsl:with-param
和参数声明修改第一个样式表 - 这不是我要求的。 1我的重点。参见 XSLT 2.0程序员参考,Michael Kay,第273页。
2请参阅规范的相关部分here或参考Michael Kay的 XSLT 2.0程序员参考,第84页。
答案 0 :(得分:5)
http://www.w3.org/TR/xslt20/#static-context
范围内变量由变量绑定元素定义 在包含元素的范围内(参见9变量和 参数)。
http://www.w3.org/TR/xslt20/#dt-variable-binding-element
The two elements xsl:variable and xsl:param are referred to as variable-binding elements
因此,在使用变量之前必须绑定它们以便它们在静态上下文中可用,否则您的XSLT程序将无法编译。
仅当您绑定参数时,参数才在范围内。为什么?因为它是这样设计的。
评估选定的
<xsl:template>
,但不更改。{ context:它使用相同的上下文项,上下文位置和上下文 size作为调用模板
以上陈述并非100%准确。使用xsl:call-template
保留一些dynamic context,例如上下文项,上下文位置和上下文大小,但它会更改变量值,这些变量值取自静态上下文的范围内变量。 每个XPath表达式都有一个静态和动态上下文。在XSLT中,表达式的静态上下文取决于包含和包含的元素。
关于focus的XPath:
动态上下文的前三个组件(上下文项,上下文位置和上下文大小)被称为表达式的焦点。焦点使处理器能够跟踪表达式正在处理的项目。
关于focus的XSLT:
当评估序列构造函数时,处理器通过一组隐含变量来跟踪正在处理哪些项目,这些隐式变量统称为焦点。
当您致电xsl:call-template
时,您正在评估序列构造函数。因为,与xsl:apply-templates
和xsl:for-each
不同,xsl:call-template
不会更改正在处理的项目,焦点没有变化。
但是,您正在评估的序列构造函数是一个不同的模板,并且因为模板不嵌套在XSLT中,所以模板中使用的XPath表达式具有与另一个模板中使用的表达式不同的范围内变量。当您使用xsl:for-each
时,这不是问题,{{1}}会更改焦点,但会保留范围内的变量。
在XSLT中,表达式的静态上下文取决于包含和包含的元素。
答案 1 :(得分:4)
很好的问题,很好问。
您期望的行为在具有动态范围的语言中很自然。但是XSLT对变量使用词法范围,而不是动态范围。
你问现在,&#34; context&#34;在XSLT中实际意味着什么,或者更准确地说,是否是被认为是上下文的一部分的参数?
简短回答:是的,该参数是静态上下文的一部分,用于其范围内的表达式(并且它的缺失是关于样式表中其他表达式的静态上下文的事实);它的值是其范围内表达式的动态上下文的一部分。并且(至关重要地)xsl:call-template
指令 会影响评估表达式的上下文。
更长的答案:具体内容可在the XSLT 2.0 spec中找到。在section 2.5中,规范告诉我们上下文分为两部分:静态上下文和动态上下文。 Section 5.4提供了完整的详细信息; section 5.4.1列出&#34;范围内变量&#34;作为静态上下文的一个组成部分。
变量的范围规则在section 9.7中给出。关键是这个:
对于所有后续兄弟及其后代,局部变量绑定元素是可见的,但有两个例外:它在任何被另一个变量绑定遮蔽的区域中不可见,并且在以xsl为根的子树中不可见:fallback指令,它是变量绑定元素的兄弟。
你遇到的明显矛盾主要依赖于这样一个前提:调用模板不会影响上下文&#34;。这个前提实际上并不正确,尽管事实上你拥有非常好的权威。
在section 10.1中,规范指出&#34; xsl:call-template
指令不会改变焦点。&#34;它并没有说明该指令会使上下文不受影响。
在你从迈克尔凯的书中引用的那篇文章中,我相信术语&#34; context&#34;也许最好将其作为&#34;上下文项目&#34;或者可能&#34;动态上下文&#34;的缩写。即使在阅读中,句子也不完全正确:因为上下文的dynamic variables
组件不同,所以被调用模板中的动态上下文与调用模板中的动态上下文不完全相同。我认为你必须在这里削减MK一些松弛:有问题的段落与他的书的XSLT 1.0版本基本没有变化,而在XSLT 1.0中,在 context 的讨论中没有明确的表示,动态绑定变量和参数到名称。但我认为你可以在下一次修订中发现MK可能希望改变的一些内容,这是公平的。
答案 2 :(得分:3)
我担心您从XSLT 2.0 Prog Ref引用的段落不太准确;它正在使用&#34; context&#34;作为&#34;动态上下文&#34;的快捷方式。写这样一本书时会有危险,如果你太精确和迂腐,它就像实际的语言规范一样难以阅读,而如果你偷工减料,那些追求精确的人可能会被误导。这里的关键是变量引用只能引用(静态)范围内的变量。被调用模板的静态上下文(定义哪些变量在范围内)当然与调用模板指令的静态上下文完全不同。
答案 3 :(得分:2)
您需要区分context
和focus
:http://www.w3.org/TR/xslt20/#dt-focus。当您使用call-template
时,焦点不会改变,请参阅http://www.w3.org/TR/xslt20/#element-call-template,其中显示“与xsl:apply-templates不同,xsl:call-template指令不会更改焦点。”。
答案 4 :(得分:0)
调用另一个模板不会改变上下文;但它确实改变了范围。您不再在调用模板中,因此在调用模板中声明的变量不适用于当前模板。