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

升级SaxonCS 11至12后ExtensionFunction失效问题求助

SaxonCS 11升级至12后自定义ExtensionFunction无法调用的问题解决

问题描述

将SaxonCS从11版本升级到12版本后,自定义扩展函数无法正常调用,编译XSLT时抛出如下异常:
Saxon.Hej.trans.XPathException: 'Cannot find a 2-argument function named Q{urn:rhea/xpath}get-svgid()'

该功能在SaxonCS 11中可正常运行,但在11到12的变更历史文档中未找到相关破坏性变更说明。

相关代码

自定义ExtensionFunctionDefinition实现

public class GetSVGID : ExtensionFunctionDefinition
{
    public override QName FunctionName => new QName("urn:rhea/xpath", "get-svgid");

    public override int MinimumNumberOfArguments => 1;

    public override int MaximumNumberOfArguments => 2;

    public override XdmSequenceType[] ArgumentTypes =>
        new[]
        {
            new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_STRING), '?'),
            new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_STRING), '?')
        };

    public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
    {
        return new(XdmAtomicType.BuiltInAtomicType(QName.XS_STRING), '?');
    }

    public override bool TrustResultType => true;

    public override ExtensionFunctionCall MakeFunctionCall()
    {
        return new GetSVGIDCall();
    }
}

原注册及编译代码

using SaxonApi = Saxon.Api;
var spro = new SaxonProcessor(); 
XsltCompiler compiler = spro.Processor.NewXsltCompiler();
compiler.ErrorReporter = error => spro.ErrorList.Add(error);
spro.Processor.RegisterExtensionFunction(new GetSVGID()); 
spro.Executable = compiler.Compile(new Uri(xsltRootPath))

包装类SaxonProcessor

public class SaxonProcessor
{
    public List<SaxonApi.Error> ErrorList = new();
    public SaxonApi.Processor Processor = new SaxonApi.Processor(true);
    public DocumentBuilder DocBuilder;
    public XsltExecutable Executable;
    public bool First;

}

XSLT相关代码片段

<xsl:template name="rhea:get-svgid">
    <xsl:param name="fname" />
    <xsl:param name="fid" />
    <xsl:param name="fidraw" />
    <xsl:choose>
      <xsl:when test="$CBmode = 'CB'">
        <xsl:value-of select="ext:get-svgid($DocIndex, $fname)"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:text>CB:</xsl:text>
        <xsl:value-of select="$fid"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>


   <xsl:variable name="rheaMediaID">
        <xsl:call-template name="rhea:get-svgid">
            <xsl:with-param name="fname">
                <xsl:value-of select="@boardno | @infoEntityIdent"/>
            </xsl:with-param>
            <xsl:with-param name="fid">
                <xsl:value-of select="$figureID"/>
            </xsl:with-param>
            <xsl:with-param name="fidraw">
                <xsl:value-of select="$figureIDraw"/>
            </xsl:with-param>
        </xsl:call-template>
    </xsl:variable>

迁移方案及问题原因

1. 调整扩展函数注册时机

SaxonCS 12对扩展函数的加载逻辑做了隐性调整:编译器初始化时会缓存已注册的扩展函数,后续注册的函数不会被识别。原代码中先创建XsltCompiler再注册函数的顺序,在12版本中会导致函数无法被编译器感知。

修正后的注册代码:

using SaxonApi = Saxon.Api;
var spro = new SaxonProcessor(); 
// 先注册扩展函数,再创建XSLT编译器
spro.Processor.RegisterExtensionFunction(new GetSVGID()); 
XsltCompiler compiler = spro.Processor.NewXsltCompiler();
compiler.ErrorReporter = error => spro.ErrorList.Add(error);
spro.Executable = compiler.Compile(new Uri(xsltRootPath))

2. 验证XSLT命名空间绑定

确保XSLT根元素已正确将ext前缀绑定到扩展函数的命名空间urn:rhea/xpath,示例如下:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:ext="urn:rhea/xpath"
                xmlns:rhea="your-rhea-namespace">

缺失该绑定会导致编译器无法匹配函数的命名空间,触发找不到函数的异常。

3. 参数类型兼容性检查

SaxonCS 12对参数类型的匹配更严格,确认XSLT中传入的$DocIndex和$fname类型与扩展函数定义的xs:string?兼容。如果传入的是节点序列而非字符串,需显式转换,例如使用string($DocIndex)。

内容的提问来源于stack exchange,提问作者Kingpin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 00:53:25