You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在XSLT 2.0/3.0中实现动态函数调用(高阶函数)?

XSLT 2.0/3.0中实现动态函数调用(高阶函数)的方法

问题场景

以下XSLT 3.0代码尝试实现动态函数调用,但在Saxon中运行失败:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:kooks="kookerella.com"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="3.0">
    
    <xsl:function name="kooks:one" as="xs:integer">
        <xsl:sequence select="1"/>
    </xsl:function>
    
    <xsl:function name="kooks:two" as="xs:integer">
        <xsl:sequence select="2"/>
    </xsl:function>

    <xsl:template match="/">
        <xsl:variable name="two" select="kooks:two()"/>
        <xsl:variable name="two_func" select="kooks:two"/>
        <xsl:variable name="two_2" select="$two_func()"/>
        <root>
            <xsl:sequence select="$two_2"/>
        </root>
    </xsl:template>    
</xsl:stylesheet>

报错信息:

唯一能通过类型检查的值是空序列。
动态函数调用目标的所需项类型为function(*),但提供的表达式{$two_func}的项类型为element(Q{kookerella.com}two)

核心原因:kooks:two在XPath语法中会被解析为选择命名空间kookerella.com下的<two>元素,而非引用同名函数,因此无法作为函数对象调用。


解决方案

1. XSLT 3.0(原生支持高阶函数)

XSLT 3.0基于XPath 3.0+,原生支持函数引用,可通过两种方式实现动态调用:

方法一:直接引用函数对象

使用function()构造器获取函数引用,适用于明确知道函数名的场景:

<xsl:template match="/">
    <xsl:variable name="two_func" select="function(kooks:two)"/>
    <xsl:variable name="two_2" select="$two_func()"/>
    <root>
        <xsl:sequence select="$two_2"/>
    </root>
</xsl:template>

方法二:动态根据QName获取函数

如果需要通过字符串动态指定函数名,可结合QName()和function-lookup()实现:

<xsl:template match="/">
    <!-- 动态定义要调用的函数名 -->
    <xsl:variable name="target-func" select="QName('kookerella.com', 'two')"/>
    <!-- 第二个参数为函数的参数个数,这里kooks:two是无参函数,传入0 -->
    <xsl:variable name="two_func" select="function-lookup($target-func, 0)"/>
    
    <xsl:if test="$two_func">
        <root>
            <xsl:sequence select="$two_func()"/>
        </root>
    </xsl:if>
</xsl:template>

2. XSLT 2.0(无原生高阶函数,间接模拟)

XSLT 2.0不支持原生高阶函数,可通过以下两种方式模拟动态调用:

方法一:分支选择函数调用

通过<xsl:choose>根据标识选择对应函数,适合有限分支的场景:

<xsl:template match="/">
    <!-- 动态标识要调用的函数 -->
    <xsl:variable name="func-key" select="'two'"/>
    <xsl:variable name="result">
        <xsl:choose>
            <xsl:when test="$func-key = 'one'">
                <xsl:sequence select="kooks:one()"/>
            </xsl:when>
            <xsl:when test="$func-key = 'two'">
                <xsl:sequence select="kooks:two()"/>
            </xsl:when>
        </xsl:choose>
    </xsl:variable>
    <root>
        <xsl:sequence select="$result"/>
    </root>
</xsl:template>

方法二:动态调用模板

将逻辑封装到命名模板中,通过动态指定模板名实现类似效果:

<xsl:template name="kooks:one-tmpl">
    <xsl:sequence select="1"/>
</xsl:template>

<xsl:template name="kooks:two-tmpl">
    <xsl:sequence select="2"/>
</xsl:template>

<xsl:template match="/">
    <xsl:variable name="target-tmpl" select="'kooks:two-tmpl'"/>
    <root>
        <xsl:call-template name="{$target-tmpl}"/>
    </root>
</xsl:template>

内容的提问来源于stack exchange,提问作者MrD at KookerellaLtd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 03:56:15