使用Saxon Processor进行XSLT-2.0 XML转换时遇XPST0017函数未找到错误
问题背景
移除Xalan依赖改用Saxon执行XSLT 2.0格式的XML转HTML操作时,PLMXML_DefaultProcessReport.xsl第22行触发错误:找不到Q{com.teamcenter.rac.cme.cmereport.CMEReportXalanExtension}new()无参函数。核心原因是原XSL使用了Xalan专属的<lxslt:component>扩展机制,Saxon不兼容该语法。
原报错相关代码
XSL文件关键片段
<?xml version="1.0"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:plm="http://www.plmxml.org/Schemas/PLMXMLSchema" xmlns:lxslt="http://www.apache.org/xslt" xmlns:setfile ="com.teamcenter.rac.cme.cmereport.CMEReportXalanExtension"> <!-- Xalan专属扩展声明 --> <lxslt:component prefix="setfile" elements="copy" functions="setFile setTcFile getCurrentDir getCurrentImanFileName getCurrentImanFileNamePrefix getNiceName"> <lxslt:script lang="javaclass" src="com.teamcenter.rac.cme.cmereport.CMEReportXalanExtension"/> </lxslt:component> <!-- 报错的函数调用 --> <xsl:param name="outDir" select="setfile:getCurrentDir(setfile:new())"/>
Java转换调用代码
{ // 1. 实例化TransformerFactory javax.xml.transform.TransformerFactory tFactory =(SAXTransformerFactory) SAXTransformerFactory.newInstance(); XslImportResolver myResolve = new XslImportResolver(); tFactory.setURIResolver( myResolve ); // 2. 处理样式表生成Transformer javax.xml.transform.Transformer transformer = tFactory.newTransformer (new javax.xml.transform.stream.StreamSource(xslLocation)); // 注册相关调试输出(原代码保留) Registry registry = Registry.getRegistry( this ); // 3. 执行转换 transformer.transform( new StreamSource( xmlLocation ), new StreamResult( new FileOutputStream( htmlLocation ) ) ); }
报错信息
Static error near {...e:getCurrentDir(setfile:new...} at char 22 in expression in xsl:param/@select on line 22 column 73 of PLMXML_DefaultProcessReport.xsl:
XPST0017: Cannot find a 0-argument function named Q{com.teamcenter.rac.cme.cmereport.CMEReportXalanExtension}new()中文翻译:
静态错误,位于PLMXML_DefaultProcessReport.xsl第22行第73列的xsl:param/@select表达式中,字符22附近:
XPST0017:找不到名为Q{com.teamcenter.rac.cme.cmereport.CMEReportXalanExtension}new()的无参函数
解决步骤
1. 替换Xalan扩展声明为Saxon兼容方式
Saxon不支持Xalan的<lxslt:component>扩展语法,需改用Saxon原生支持的Java扩展命名空间。修改XSL的命名空间声明,移除Xalan相关的lxslt命名空间和标签:
<?xml version="1.0"?> <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:plm="http://www.plmxml.org/Schemas/PLMXMLSchema" xmlns:setfile="java:com.teamcenter.rac.cme.cmereport.CMEReportXalanExtension"> <!-- 移除原有的<lxslt:component>标签 -->
2. 调整扩展函数调用逻辑
Saxon调用Java实例方法时,需通过类名直接实例化对象(前提是类有public无参构造函数)。修改报错的参数声明:
<xsl:param name="outDir" select="setfile:getCurrentDir(setfile:CMEReportXalanExtension())"/>
如果getCurrentDir可以改为静态方法,可进一步简化为直接调用静态方法,无需实例化:
<xsl:param name="outDir" select="setfile:getCurrentDir()"/>
3. (可选)Java代码中显式注册扩展函数
若直接使用java:前缀的方式不生效,可在Java代码中显式向Saxon注册扩展函数,确保函数能被识别:
// 直接实例化Saxon的TransformerFactory实现 net.sf.saxon.TransformerFactoryImpl tFactory = new net.sf.saxon.TransformerFactoryImpl(); // 注册setfile:new()扩展函数 tFactory.getConfiguration().registerExtensionFunction(new net.sf.saxon.lib.ExtensionFunction() { @Override public QName getFunctionQName() { // 对应XSL中的setfile命名空间和new函数名 return new QName("com.teamcenter.rac.cme.cmereport.CMEReportXalanExtension", "setfile", "new"); } @Override public SequenceType[] getArgumentTypes() { return new SequenceType[0]; // 无参数 } @Override public SequenceType getResultType() { // 返回值为CMEReportXalanExtension对象 return SequenceType.makeSequenceType(ItemType.OBJECT_TYPE, OccurrenceIndicator.ONE); } @Override public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException { // 创建扩展类实例并返回 return new ObjectValue<>(new com.teamcenter.rac.cme.cmereport.CMEReportXalanExtension()); } }); // 后续设置URIResolver、创建Transformer等代码保持不变 XslImportResolver myResolve = new XslImportResolver(); tFactory.setURIResolver( myResolve ); javax.xml.transform.Transformer transformer = tFactory.newTransformer(new javax.xml.transform.stream.StreamSource(xslLocation)); Registry registry = Registry.getRegistry( this ); transformer.transform( new StreamSource( xmlLocation ), new StreamResult( new FileOutputStream( htmlLocation ) ) );
4. 验证扩展类的可访问性
确保com.teamcenter.rac.cme.cmereport.CMEReportXalanExtension类:
- 存在于Saxon的类路径中
- 拥有public无参构造函数
- 被调用的
getCurrentDir等方法为public权限
内容的提问来源于stack exchange,提问作者ashish sharma

