XSL中的“调用模板”和“应用模板”之间有什么区别?


118

我是XSLT的新手,所以我对这两个标签有些困惑,

<xsl:apply-templates name="nodes">

<xsl:call-template select="nodes"> 

那么您能列出它们之间的区别吗?

Answers:


166

<xsl:call-template> 与在传统编程语言中调用函数非常相似。

您可以在XSLT中定义函数,例如这种简单的输出字符串的函数。

<xsl:template name="dosomething">
  <xsl:text>A function that does something</xsl:text>
</xsl:template>

可以通过调用此函数<xsl:call-template name="dosomething">

<xsl:apply-templates>有点不同,它是XSLT的真正功能:它可以使用任意数量的XML节点(无论您在select属性中定义的是什么),都可以对其进行迭代(这很重要:apply-templates就像一个循环!)并找到匹配的模板对于他们:

<!-- sample XML snippet -->
<xml>
  <foo /><bar /><baz />
</xml>

<!-- sample XSLT snippet -->
<xsl:template match="xml">
  <xsl:apply-templates select="*" /> <!-- three nodes selected here -->
</xsl:template>

<xsl:template match="foo"> <!-- will be called once -->
  <xsl:text>foo element encountered</xsl:text>
</xsl:template>

<xsl:template match="*"> <!-- will be called twice -->
  <xsl:text>other element countered</xsl:text>
</xsl:template>

这样,您就可以放弃对XSLT处理器的一点控制-不必确定程序流向何处,而是可以通过为当前正在处理的节点找到最合适的匹配项来实现。

如果多个模板可以匹配一个节点,则具有更特定匹配表达式的模板将获胜。如果存在多个具有相同特异性的匹配模板,则最后声明的那个为准。

您可以将更多精力放在开发模板上,而花费更少的时间进行“管道”。您的程序将变得更强大,更模块化,嵌套深度更少,速度更快(因为XSLT处理器针对模板匹配进行了优化)。

XSLT可以理解的一个概念是“当前节点”的概念。随着<xsl:apply-templates>与每个迭代当前节点的移动,而<xsl:call-template>不会改变当前节点。即,.被调用模板中的指代与.调用模板中相同的节点。套用范本不是这种情况。

这是基本区别。模板还有其他一些方面会影响它们的行为:modepriority,模板可以同时具有namematch。模板是否已导入(<xsl:import>)也都会产生影响。这些是高级用途,您可以在到达那里时进行处理。


5
@Tomalak:好答案!但是,该语句:“ xsl:apply-templates是一个循环”是不正确的。在任何正式的W3C规范中都没有迹象表明<xsl:apply-templates>必须将其实现为循环-相反,它可以并行实现,因为节点列表的不同节点上的不同应用程序是绝对相互独立的。
Dimitre Novatchev 2010年

8
@Dimitre:我的意思是说:从最终用户的角度来看,它的<xsl:apply-templates>行为就像一个循环。作为XSLT程序员,XSLT处理器端的实现差异不会影响我,对于并行化和迭代实现而言,结果是绝对相同的。但是对于具有强制性背景的XSLT新手来说,它有助于将其设想<xsl:apply-templates>为一种for-each循环,即使-从技术上来说不是这样。
Tomalak 2010年

@Tomalak:虽然这对于新手XSLT程序员可能有用,但我认为这经常会误导他们,因为他们认为他们可以重用“循环执行”中累积的状态信息。
Dimitre Novatchev 2010年

@Tomalak:基于这些事实,我认为使用“
thsl

@Tomalak:循环是迭代,有些东西apply-templatescall-template指令都不适合。它们是XSLT中的递归机制。正如Dimitre回答的那样,应用模板是多态性或数据驱动机制。

15

要添加@Tomalak的良好答案,请执行以下操作:

以下是一些未提及的重要差异

  1. xsl:apply-templatesxsl:call-templatesxsl:for-each仅仅因为我们不知道将在选择的节点上应用什么代码所以它甚至甚至 更丰富,更深入。--在一般情况下,此代码对于节点列表的不同节点将有所不同。

  2. 可以在编写xsl:apply templates 之后,由不认识原始作者的人来编写将要应用的代码

如果XSLT没有该<xsl:apply-templates>指令,则FXSL库无法在XSLT中实现高阶函数(HOF)

摘要:模板和<xsl:apply-templates>指令是XSLT如何实现和处理多态的。

参考:请参见整个主题:http : //www.biglist.com/lists/lists.mulberrytech.com/xsl-list/archives/200411/msg00546.html


8

xsl:apply-templates通常(但不是必须)用于处理具有所有适用模板的当前节点的所有子节点或子节点的子集。这支持XSLT应用程序的递归性,该递归性与已处理XML的(可能)递归性相匹配。

xsl:call-template另一方面,它更像是正常的函数调用。您通常只使用一个或多个参数来执行一个(命名)模板。

因此,xsl:apply-templates如果我想截取一个有趣的节点并(通常)向输出流中注入一些东西,我就使用它。一个典型的(简化的)例子是

<xsl:template match="foo">
  <bar>
    <xsl:apply-templates/>
  </bar>
</xsl:template>

xsl:call-template我通常会解决一些问题,例如将一些子节点的文本添加到一起,将选择的节点集转换为文本或其他节点集之类的东西-您会为此编写专门的可重用函数。

编辑:

作为对特定问题文本的补充说明:

<xsl:call-template name="nodes"/> 

这将调用一个名为“节点”的模板:

    <xsl:template name="nodes">...</xsl:template>

这与以下语义不同:

<xsl:apply-templates select="nodes"/>

...将所有模板应用于名称为“ nodes”的当前XML节点的所有子级。


2

功能确实很相似(除了调用语义外,在调用语义中call-template需要一个name属性和一个相应的名称模板)。

但是,解析器将无法以相同的方式执行。

MSDN

与不同<xsl:apply-templates><xsl:call-template>不会更改当前节点或当前节点列表。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.