SaxonJS中fn:transform返回非文档节点致XPath执行报错
问题原因
你的转换结果是元素节点,而非完整的文档节点(Document Node),这是XPath报错的核心:
- XPath的
//语法要求上下文为文档节点,它会从文档节点的所有后代中匹配内容;如果上下文是元素节点,/指向元素本身,//无法按预期解析,直接抛出"Root node for '/' must be a document node"错误。 - 源文档是完整的文档节点(带有
documentElement属性),所以//*[@someAttr]/name能正常执行;而转换结果是裸元素节点,XDM结构中没有外层文档节点包装,因此触发报错。
之所以转换结果是元素节点,大概率是你的XSLT1.0模板未显式处理文档节点:XSLT1.0的内置模板对文档节点会直接将逻辑传递给子元素,最终输出根元素节点,而非包含它的文档节点。
解决方法
方法1:修改XSLT模板,输出完整文档节点
添加匹配文档节点的模板,显式保留文档节点结构:
<!-- 匹配文档节点,保留外层文档节点 --> <xsl:template match="/"> <xsl:copy> <xsl:apply-templates/> </xsl:copy> </xsl:template> <!-- 原有复制模板,移除@cmyk属性 --> <xsl:template match="*"> <xsl:copy> <xsl:copy-of select="@*[not(local-name()='cmyk')]"/> <xsl:apply-templates/> </xsl:copy> </xsl:template>
该模板会复制文档节点本身,再处理子元素,最终转换结果为完整的文档节点。
方法2:手动将元素节点包装为文档节点
若不想修改XSLT,可在转换后通过序列化再解析的方式包装文档节点:
// 假设transformResult是fn:transform返回的元素节点 const serialized = SaxonJS.XPath.evaluate(`fn:serialize($result)`, [], { params: { result: transformResult } }); const docNode = SaxonJS.XPath.evaluate(`fn:parse-xml($serialized)`, [], { params: { serialized: serialized } });
处理后的docNode是完整文档节点,可正常执行//开头的XPath表达式。
方法3:调整fn:transform调用参数
调用SaxonJS的fn:transform时,指定返回文档节点:
const transformOptions = { stylesheetLocation: 'your-xslt.xsl', sourceNode: sourceDoc, delivery: 'document' // 强制返回文档节点 }; const resultDoc = SaxonJS.XPath.evaluate(`fn:transform($options)`, [], { params: { options: transformOptions } });
注:delivery是SaxonJS对fn:transform的扩展参数,请确保你的SaxonJS版本支持该配置。
内容的提问来源于stack exchange,提问作者Sander_P
相关产品推荐
相关产品推荐

