XSLT 函数返回不同的结果 [Saxon-EE vs Saxon-HE/PE] [英] XSLT function returns different results [Saxon-EE vs Saxon-HE/PE]

查看:36
本文介绍了XSLT 函数返回不同的结果 [Saxon-EE vs Saxon-HE/PE]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在使用各种版本的 Saxon-Processor 进行纯 XSL 转换.下面是我的简短样式表,根据我的问题的需要进行了简化:

I am currently working on a pure XSL-Transformation with Saxon-Processor in various versions. Below is my short stylesheet, simplified for the needs of my question:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:foo="bar">

    <xsl:output encoding="UTF-8" method="text"/>

    <xsl:template match="/">
        <xsl:text>Call of func_1: </xsl:text>        
        <xsl:value-of select="foo:func_1()"/>

        <xsl:text>&#xA;Call of func_1: </xsl:text>
        <xsl:value-of select="foo:func_1()"/>

        <xsl:text>&#xA;Call of func_1: </xsl:text>
        <xsl:value-of select="foo:func_1()"/>

        <xsl:text>&#xA;Call of func_2: </xsl:text>
        <xsl:value-of select="foo:func_2()"/>
    </xsl:template>

    <xsl:function name="foo:func_1" as="xs:string">
        <!-- do some other stuff -->
        <xsl:value-of select="foo:func_2()"/>
    </xsl:function>

    <xsl:function name="foo:func_2" as="xs:string">
        <xsl:variable name="node">
            <xsl:comment/>
        </xsl:variable>
        <xsl:sequence select="generate-id($node)"/>
    </xsl:function>

</xsl:stylesheet>

说明

foo:func_1 是一个包装函数,用于返回第二个函数的值 + 做其他事情,可以忽略.这个函数调用其他函数的概念是强制性的!

foo:func_1 is a wrapper function to return the value of a second function + doing other stuff, which can be ignored. this concept of function calls other function is mandatory!

foo:func_2 为元素生成唯一的 id.该元素是在名为node"的局部作用域变量中创建的.

foo:func_2 generates a unique id for an element. This element is created in a local scoped variable named "node".

基于撒克逊版本的不同结果

预期结果:

Call of func_1: d2
Call of func_1: d3
Call of func_1: d4
Call of func_2: d5

Saxon-EE 9.6.0.7/Saxon-EE 9.6.0.5 结果

Call of func_1: d2
Call of func_1: d2
Call of func_1: d2
Call of func_2: d3

Saxon-HE 9.6.0.5/Saxon-PE 9.6.0.5/Saxon-EE 9.5.1.6/Saxon-HE 9.5.1.6 结果

like expected

问题/进一步深入

我尽可能自己调试了问题.如果我将函数func_1"中的 xsl:value-of 更改为 xsl:sequence,所有版本的结果都将相同 [如预期的那样].但这不是我的本意!

I debugged the problem on my own as far as i could. IF i would change the xsl:value-of in function "func_1" to xsl:sequence, the results will be the same for all versions [like expected]. But that's not my intention!

我想了解,在整个 Saxon 版本中 xsl:value-ofxsl:sequence 之间有什么区别.是否有任何隐藏"缓存?在我的情况下,使用 xsl:sequencexsl:value-of 的正确方法是什么.[顺便说一句:我已经知道了,value-of 创建了一个带有 select 语句结果的文本节点.序列可以是对节点或原子值的引用.不要解决我的问题afaik]

I want to understand, what is the difference between xsl:value-of and xsl:sequence throughout Saxon versions. Is there any "hidden" caching? What is the correct way to work with xsl:sequence and xsl:value-of in my case. [btw: i know already, value-of creates a text node with the result of the select-statement. sequence could be a reference to a node or atomic value. don't solve my problem afaik]

推荐答案

这是一个长期存在且相当深刻的问题.在纯函数式语言中,使用相同的参数两次调用纯函数总是会产生相同的结果.这使得许多优化成为可能,例如,如果参数不变,则将函数调用从循环中拉出,或者如果函数调用不是递归的,则内联函数调用.不幸的是,XSLT 和 XQuery 函数并不是完全纯函数式的:特别是,它们被定义为如果函数创建新节点,则调用该函数两次会产生不同的节点(f() 是 f()返回 false).

This is a long-standing and rather deep problem. In a pure functional language, calling a pure function twice with the same arguments always produces the same result. This makes many optimizations possible, such as pulling a function call out of a loop if the arguments are invariant, or inlining a function call if it's not recursive. Unfortunately XSLT and XQuery functions aren't quite purely functional: in particular, they are defined so that if the function creates new nodes, then calling the function twice produces different nodes (f() is f() returns false).

Saxon 优化器非常努力地在这些约束范围内尽可能地进行优化,特别是通过识别创建新节点的函数并避免对此类函数进行激进的优化.

The Saxon optimizer tries quite hard to optimize as far as it can within these constraints, in particular by recognizing functions that create new nodes and avoiding aggressive optimization of such functions.

但规范本身并不是 100% 规定的.例如,如果在您的示例中存在一个不依赖于函数参数的局部变量,我认为规范为实现提供了许可,即变量的值是每次评估中的相同节点还是新节点.

But the spec itself isn't 100% prescriptive. For example, if as in your example there is a local variable with no dependencies on function arguments, I think the spec gives license to the implementation as to whether the value of the variable is the same node on each evaluation, or is a new node.

正如 Martin 所说,新的 XSLT 3.0 属性 new-each-time 试图控制这一点:如果每次调用函数时你真的想要一个新节点,你应该指定 new-each-time="yes".

As Martin says, the new XSLT 3.0 attribute new-each-time is an attempt to get this under control: if you really want a new node each time the function is called, you should specify new-each-time="yes".

注意:

这里发生的特定优化(您可以通过运行 -explain 选项看到)是 func_2 首先被内联,然后它的主体被提取到一个全局变量中.一些版本正在这样做,而其他版本则没有 - 它可能对微小的变化非常敏感.最好的建议是不要依赖具有这种副作用的函数.如果您解释了您的真正问题,这将有所帮助,那么也许我们可以找到一种对语言语义中的边缘情况不那么敏感的方法.

The specific optimization that is happening here (which you can see by running with the -explain option) is that func_2 is first inlined, and then its body is being extracted into a global variable. Some releases are doing this and others aren't - it can be very sensitive to minor changes. The best advice is not to depend on functions having this kind of side-effect. It would help if you explained your real problem, then perhaps we could find an approach that isn't so sensitive to edge cases in the language semantics.

这篇关于XSLT 函数返回不同的结果 [Saxon-EE vs Saxon-HE/PE]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆