XSL 递归调用 - xsl:functions vs xsl:template with call template

Posted

技术标签:

【中文标题】XSL 递归调用 - xsl:functions vs xsl:template with call template【英文标题】:XSL recursive call - xsl:functions vs xsl:template with call template 【发布时间】:2011-08-15 04:28:56 【问题描述】:

我有基本的查询。我一直在使用 xsl:template 并使用 call tempate 对模板进行递归调用。我看到 xsl:function 也可以像递归模板调用一样进行递归函数调用并实现相同的功能。何时应使用 xsl:function 以及何时应使用 xsl:template。我不确定两者之间有什么区别以及何时应该使用它们。他们每个人的特点是什么。有人可以帮助我更好地理解这一点。

【问题讨论】:

好问题,+1。有关解释、比较和建议,请参阅我的答案。 【参考方案1】:

我发现 Dimitre 的回复 - http://www.stylusstudio.com/xsllist/200811/post00400.html - 很有帮助。

使用<xsl:function/>的好处:

    可组合性。

    在使用它作为参数的表达式中看起来很棒,因为 返回值或作为部分 申请。

    可读性(紧凑性)和可维护性。

    更松散的耦合(不依赖于隐式上下文节点)

    可以在 XPath 表达式中引用

不足之处:

    参数仅按位置标识(而不是按名称)

    可能不纯(可能有副作用,例如创建新节点) 只看一个表达式 引用这个函数的人可能 不明白它有一面 影响。然而这种可能性 如果适当,可以消除混淆 使用命名。

我总是倾向于使用<xsl:function/>。 在函数创建的情况下 新节点我遵循的约定 以 字符串“make”,如makePerson()

【讨论】:

【参考方案2】:

从概念上讲,xsl:apply-templates 是一个具有多态函数的映射,表示您声明的所有规则。 xsl:function 声明了一个“常规”函数,您可以在任何其他接受 XPath 表达式的指令或声明中使用。 xsl:call-template 指令“调用”一个特定的命名模板(您可以在某种程度上将其视为一个函数)。

因此,关于评估上下文如何参与其中存在差异:xsl:apply-templates 定义一个新的上下文列表,从中获取上下文节点以及邻近位置; xsl:function 没有定义上下文节点(依赖它是错误的); xsl:call-template 不会更改评估上下文。

其他明显的区别是它们与输出的关系:xsl:apply-templatesxsl:call-template 作为 XSLT 指令输出它们构造的序列; xsl:function 不是 XPath 表达式的一部分。

【讨论】:

@Alejandro:我在您的回答中发现两个有问题的陈述(不完全正确)。 1) "xsl:function 没有定义上下文节点(依赖它是错误的);" 更准确地说,如果在主体中遇到相对 XPath 表达式,XSLT 处理器必须发出错误信号功能。 2) “xsl:function 作为 XPath 表达式的一部分,它没有。(输出一个构造的序列)”。这不是真的。 xsl:function 可以创建节点并返回它们——我使用这种技术。是的,xsl:function 可能会产生副作用。 @Dimitre: From w3.org/TR/xslt20/#stylesheet-functions "在样式表函数的主体中,焦点最初是未定义的;这意味着任何引用上下文项、上下文位置或上下文大小的尝试是不可恢复的动态错误。” 关于两个:输出到结果树的不是函数,而是 XSLT 指令。关于副作用,这可能是有争议的:即使是构造新节点作为结果的函数也会为相同的参数构造相同的结果,除了它可能不具有相同的节点标识。 @Dimitre:主题:看起来有一个重大的重新标记将所有xpathengines 标记更改为xpath,甚至更改了版本的归属(如果我用xpathengines 标记现在它说我已经用xpath标记了它)。关注meta.stackexchange.com/questions/89005/… 的讨论 @alejandro:当函数返回构造节点的 generate-id() 时,它会为相同的参数返回不同的结果——在每次调用时。 @Dimitre:这就是我所说的:它返回相同的节点(深等于)但它们可能具有相同的身份(请注意,不能保证无论哪种方式。在某些规范中,此声明是明确的。)这并不否认您可以声明一个不稳定的函数并且(就像在任何声明性语言中一样)您可以通过幺半群安全地对其进行建模。【参考方案3】:

这是 how I replied to a similar question 差不多 3 年前:

使用<xsl:function/>的好处:

    可组合性。

    在使用它作为参数的表达式中看起来很棒,因为 返回值或作为部分 申请。

    可读性(紧凑性)和可维护性。

    更松散的耦合(不依赖于隐式上下文节点)

    可以在 XPath 表达式中引用

不足之处:

    参数仅按位置标识(而不是按名称)

    可能不纯(可能有副作用,例如创建新节点) 只看一个表达式 引用这个函数的人可能 不明白它有一面 影响。然而这种可能性 如果适当,可以消除混淆 使用命名。

我总是倾向于使用<xsl:function/>。 在函数创建的情况下 新节点我遵循的约定 以 字符串“make”,如makePerson()

我只能补充:

尽可能使用<xsl:function>

在 XPath 3.0 中,函数是语言的一等数据类型(又名 HOF -- 高阶函数)。 它们可以作为参数传递或作为结果返回给/从其他功能。

这是使用命名模板的一个令人难以置信的强大飞跃

【讨论】:

【参考方案4】:
Templates are useful when you have the requirement to store the results of each recursion into a variable as a attribute ( at the end of each recursion before calling the next ).

**Example:**

    <xsl:variable name="test">
     <record>
        <xsl:call-template name="templateRecursion">
              <xsl:with-param name="xyz" select="xyz"/>   
        </xsl:call-template>
     <record>
    </xsl:variable>

**templateRecursion:**

    <xsl:template name="templateRecursion">

    <!-- Do processing -->
     <xsl:attribute name="" value=""

    </xsl:template>

So, the variable test will have 

    <record>
     <attribute_name="" value=""/>
      .
      .
    </record>

【讨论】:

以上是关于XSL 递归调用 - xsl:functions vs xsl:template with call template的主要内容,如果未能解决你的问题,请参考以下文章

XSLT/XSL 递归嵌套元素

XSL 中的递归替换

在 Saxon 中处理无限递归 XSL

XSL-FO:在页面序列中调用xsl-template?

在 XSL 中定义 PHP-Function 并调用它。可能的?如何?

XSL 在某个字符后显示属性