关于调用模板的参数的"上下文"的含义

Mat*_*ler 4 xslt parameters xslt-2.0

我想我已经很好地掌握了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>
Run Code Online (Sandbox Code Playgroud)

为什么模板B不会自动采用模板A的参数作为上下文的一部分?我的理由如下.

显然,调用模板不会以任何方式影响上下文:

<xsl:template>更改上下文的情况下评估所选内容:它使用与调用模板1相同的上下文项,上下文位置和上下文大小


现在,"上下文"在XSLT中实际意味着什么,或者更确切地说,是一个被认为是上下文的一部分的参数?形成背景的事物包括2:

  • 作为静态上下文的一部分,在计算表达式的范围内的所有变量声明(xsl:variablexsl: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>
Run Code Online (Sandbox Code Playgroud)

但是很明显,只有第二个是正确的,而第一个产生关于缺失变量声明的两个错误.如果模板调用不更改上下文并且参数被视为上下文的一部分,为什么必须在调用模板中显式声明参数?

为清楚起见:

  • 我知道如何修改第一个样式表xsl:with-param和参数声明 - 这不是我要求的.
  • 我知道XSLT 2.0中的隧道参数 - 您不必解释它们或建议它们作为替代方案.我不是要求在模板中使用未声明的参数的方法 - 我想知道为什么它们首先不可用.

1我的重点.请参阅XSLT 2.0程序员参考,Michael Kay,第273页
.2请参阅此处的相关部分或参考Michael Kay的XSLT 2.0程序员参考,第84f页.

Max*_*oro 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
Run Code Online (Sandbox Code Playgroud)

因此,在使用变量之前必须绑定它们,以便它们在静态上下文中可用,否则您的XSLT程序将无法编译.


仅当您绑定参数时,参数才在范围内.为什么?因为它是这样设计的.

<xsl:template>不更改上下文的情况下评估选定内容:它使用与调用模板相同的上下文项,上下文位置和上下文大小

以上陈述并非100%准确.使用xsl:call-template保留一些动态上下文,例如上下文项,上下文位置和上下文大小,但它会更改变量值,这些变量值取自静态上下文的范围内变量.每个XPath表达式都有一个静态和动态上下文.在XSLT中,表达式的静态上下文取决于包含和包含的元素.


关于焦点的 XPath :

动态上下文的前三个组件(上下文项,上下文位置和上下文大小)被称为表达式的焦点.焦点使处理器能够跟踪表达式正在处理的项目.

关于焦点的 XSLT :

当评估序列构造函数时,处理器通过一组隐含变量来跟踪正在处理哪些项目,这些隐式变量统称为焦点.

当你打电话时,xsl:call-template你正在评估一个序列构造函数.因为,不像xsl:apply-templatesxsl:for-each,xsl:call-template不会改变正在处理的项目,有焦点没有变化.

但是,您正在评估的序列构造函数是一个不同的模板,并且因为模板不嵌套在XSLT中,所以模板中使用的XPath表达式具有与另一个模板中使用的表达式不同的范围内变量.使用时不会出现问题xsl:for-each,这会改变焦点,但会保留范围内的变量.

在XSLT中,表达式的静态上下文取决于包含和包含的元素.


C. *_*een 5

很好的问题,问得很好。

您期望的行为在具有动态范围的语言中是自然的。但是 XSLT 对变量使用词法作用域,而不是动态作用域。

您问现在,“上下文”在 XSLT 中的实际含义是什么,或者更准确地说,参数是否被视为上下文的一部分?

简短回答:是的,参数是静态上下文的一部分,对于其范围内的表达式(并且它的缺失是关于样式表中其他地方表达式的静态上下文的事实);它的值是其范围内表达式的动态上下文的一部分。并且(至关重要)xsl:call-template指令确实会影响计算表达式的上下文。

更长的答案:细节可以在XSLT 2.0 规范中找到。在2.5 节中,规范告诉我们上下文分为两部分:静态上下文和动态上下文。 第 5.4 节提供了完整的细节;第 5.4.1 节将“范围内变量”列为静态上下文的一个组成部分。

变量的作用域规则在9.7 节中给出。关键是这样的:

局部变量绑定元素对所有后续兄弟及其后代可见,有两个例外:它在被另一个变量绑定遮蔽的任何区域中不可见,并且在以 xsl:fallback 指令为根的子树中不可见那是变量绑定元素的兄弟。

您遇到的明显矛盾主要取决于“调用模板不会影响上下文”的前提。这个前提实际上是不正确的,尽管事实上你有很好的权威。

第 10.1 节中,规范说“xsl:call-template指令不会改变焦点”。它并不是说指令不影响上下文。

在您从 Michael Kay 的书中引用的那段话中,我认为“上下文”一词最好被视为“上下文项”或“动态上下文”的缩写。即使在那个句子中阅读也不太正确:因为dynamic variables上下文的组成部分不同,被调用模板中的动态上下文与调用模板中的动态上下文不完全相同。我认为你必须在这里让 MK 松懈一些:有问题的段落与他的书的 XSLT 1.0 版本基本没有变化,并且在 XSLT 1.0 中,在讨论context 时,没有明确表示变量的动态绑定和名称的参数。但我认为可以公平地说,您在 MK 可能希望在下一个修订版中更改的书中找到了一些内容。