Saxon升级至10.6后xsl:result-document报错求助
问题:Saxon从8.7升级到10.6后xsl:result-document报错
近期将Saxon版本从8.7升级至10.6,此前在8.7版本中xsl:result-document可正常工作,现遇到报错,文件生成部分内容后程序失败。
相关代码与信息
XML输入格式
<?xml version="1.0" encoding="UTF-8"?> <Statements> <title>This is an example document</title> <Statement> <Invoice>1234567</Invoice> <Name>ABC</Name> </Statement> <Statement> <Invoice>9876543</Invoice> <Name>XYZ</Name> </Statement> </Statements>
XSLT片段
<xsl:template name="EnhanceAccount"> <xsl:result-document href="/data/ebpp/{$FileName}_EnhancedAccountInfo.jr1" method="text"> <xsl:text>InvoiceNumber</xsl:text> <xsl:text> </xsl:text> <xsl:for-each select="//Statement"> <xsl:value-of select="InvoiceNumber"/> <xsl:text> </xsl:text> </xsl:for-each> </xsl:result-document> </xsl:template>
报错信息
net.sf.saxon.trans.XPathException: The system identifier of the principal output file is unknown at net.sf.saxon.lib.StandardOutputResolver.resolve(StandardOutputResolver.java:89) at net.sf.saxon.lib.OutputURIResolverWrapper.resolve(OutputURIResolverWrapper.java:58) at net.sf.saxon.expr.instruct.ResultDocument.makeReceiver(ResultDocument.java:528) at net.sf.saxon.expr.instruct.ResultDocument.processLeft(ResultDocument.java:477)
已生成的文件内容
InvoiceNumber 1234567
Java调用代码
File stylesheet = new File(enhanceAccountTemplate); TransformerFactory transformerFactory = TransformerFactory.newInstance(); Templates cachedXSLT = transformerFactory.newTemplates(new StreamSource(stylesheet)); Transformer transformer = cachedXSLT.newTransformer(); transformer.setParameter("FileName", inpfile); Source src = new StreamSource(inputStream); Result res = new StreamResult(out); transformer.transform(src, res);
问题原因及解决方案
核心原因
Saxon 9.0及以上版本对xsl:result-document的输出解析逻辑做了调整:当主输出结果(即transform方法传入的Result对象)未设置**系统标识符(System ID)**时,即使xsl:result-document使用绝对路径,Saxon的StandardOutputResolver依然会依赖主输出的系统ID完成路径解析,从而抛出该错误。而Saxon 8.7版本没有这个强制校验逻辑。
另外你的XSLT存在节点选择错误:XML中Statement下的节点是<Invoice>,但XSLT里用了select="InvoiceNumber",这会导致循环中大部分内容无法正确输出。
解决方案
- 为主输出Result设置系统标识符
修改Java代码中StreamResult的初始化逻辑,添加合法的系统ID(可以是真实文件路径,也可以是虚拟URI):
File stylesheet = new File(enhanceAccountTemplate); TransformerFactory transformerFactory = TransformerFactory.newInstance(); Templates cachedXSLT = transformerFactory.newTemplates(new StreamSource(stylesheet)); Transformer transformer = cachedXSLT.newTransformer(); transformer.setParameter("FileName", inpfile); Source src = new StreamSource(inputStream); Result res = new StreamResult(out); // 添加系统ID,可使用虚拟URI或真实文件路径 res.setSystemId("file:/dummy/main-output"); transformer.transform(src, res);
- 修正XSLT中的节点选择错误
将XSLT里的select="InvoiceNumber"改为select="Invoice",匹配XML中的实际节点:
<xsl:template name="EnhanceAccount"> <xsl:result-document href="/data/ebpp/{$FileName}_EnhancedAccountInfo.jr1" method="text"> <xsl:text>InvoiceNumber</xsl:text> <xsl:text> </xsl:text> <xsl:for-each select="//Statement"> <xsl:value-of select="Invoice"/> <!-- 修正节点名称 --> <xsl:text> </xsl:text> </xsl:for-each> </xsl:result-document> </xsl:template>
内容的提问来源于stack exchange,提问作者Pooja
相关产品推荐
相关产品推荐

