升级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
相关产品推荐
相关产品推荐

