如何将 XSLT 2 样式表模块中定义的函数公开给 fn:transform?

How to expose functions defined in XSLT 2 stylesheet module to fn:transform?

XPath 3.1 transform 函数允许您应用模板或调用命名模板或调用样式表函数。

但是,当我尝试使用现有的 XSLT 2.0 样式表模块(例如,http://www.xsltfunctions.com/ and available as XSLT 2 at http://www.xsltfunctions.com/xsl/functx-1.0-doc-2007-01.xsl 中记录的 functx 模块)时,在 xsl:stylesheet 中以 XSLT 2 方式声明了许多函数或 xsl:transform 根元素,但不使用 XSLT 3 xsl:package 构造,我无法说服 Saxon 9.8 或 9.9 运行 使用 transform 函数声明的任何函数并使用 initial-function 参数,因为我总是收到错误消息“XTDE0041:无法从外部调用函数 foo#2,因为它不是 public”。

示例可能是:

transform(
map {
'stylesheet-location': 'http://www.xsltfunctions.com/xsl/functx-1.0-doc-2007-01.xsl',
'delivery-format': 'raw',
'initial-function': QName('http://www.functx.com', 'substring-before-match'),
'function-params': ['abc-def-ghi', '[dg]']
})?output

但给出上述错误。

我发现的唯一解决方法是动态构建(例如在 XQuery 中)一个 XSLT 3 包,导入 functx 模块并使用 xsl:expose 生成函数 public:

let $functxNs := 'http://www.functx.com',
    $functxLoc := 'http://www.xsltfunctions.com/xsl/functx-1.0-doc-2007-01.xsl',
    $libPackage := <xsl:package
        name="http://example.com/import-functx"
        package-version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="3.0"
        xmlns:functx="http://www.functx.com">
        <xsl:expose
            component="function"
            names="functx:*"
            visibility="public"/>
        <xsl:import
            href="{$functxLoc}"/>
    </xsl:package>
return
    transform(
    map {
        'stylesheet-node': $libPackage,
        'delivery-format': 'raw',
        'initial-function': QName('http://www.functx.com', 'substring-before-match'),
        'function-params': ['abc-def-ghi', '[dg]']
    })?output

这可行,但需要使用 XPath 3.1 的宿主语言(如上面的 XQuery 3.1)。

有没有更简单的方法来使用 transform 函数和 initial-function 以及声明函数的现有 XSLT 2 样式表模块?

根据 Michael Kay 在 https://saxonica.plan.io/boards/3/topics/7540 中的解释,任何没有 visibility 属性的命名函数在默认情况下都被执行样式表的 fn:transform 函数视为私有,无论该函数是否出现在显式包或隐式包(即带有 xsl:stylesheetxsl:transform 的样式表模块)。

基于此,确实需要重写 XSLT 2 代码以添加 visibility 应该可由 fn:transform 执行调用的函数属性,或者需要 "wrap" 现有 XSLT 2 代码到允许更改可见性的 XSLT 3 构造中,就像我在尝试使用 xsl:import 导入 XSLT 2 代码并使用 xsl:expose 确保导入函数时所做的那样 public 例如<xsl:expose component="function" names="functx:*" visibility="public"/>。然而,除了 XPath 3.1 fn:transform.

之外,后者还需要使用 XSLT 3 或 XQuery 3