我在一个文件夹中有多个 xml 文件,当我尝试使用 saxon 处理每个文件时,文件夹中的文件数量将在运行时连同文件名和路径传递给 xslt:当我收到空指针异常时,我尝试在没有 while 循环的情况下使用单个文件并且代码有效。
我正在共享 xml 和 xslt 的简化版本以显示我面临的问题。我正在使用 Saxon 11.2 EE
XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:f="http://www.test.com/function" version="3.0" exclude-result-prefixes="#all" xmlns:saxon="http://saxon.sf.net/" extension-element-prefixes="saxon" >
<xsl:output method="text" omit-xml-declaration="no" indent="yes" />
<xsl:mode streamable="yes" on-no-match="shallow-skip" />
<xsl:param name="inputPath"/>
<xsl:param name="filename"/>
<xsl:param name="numberOfFiles"/>
<xsl:variable name="fileCount" select="0" saxon:assignable="yes"/>
<xsl:variable name="fullFileName" select="''" saxon:assignable="yes"/>
<xsl:template match="Input">
<saxon:while test="$numberOfFiles > $fileCount">
<saxon:assign name="fullFileName" select="concat($inputPath,$filename,'_',$fileCount,'.xml')"/>
<out><xsl:value-of select="$fullFileName"/></out>
<xsl:apply-templates select="doc($fullFileName)/Input/InData/InfoArray/copy-of(.)" mode="s" />
<saxon:assign name="fileCount" select="$fileCount+1"/>
</saxon:while>
</xsl:template>
<xsl:template match="Info/UnitSellPrice" mode="s">
<price><xsl:value-of select="."/></price>
</xsl:template>
</xsl:stylesheet>
XML 1:
<?xml version="1.0" encoding="UTF-8"?>
<Input>
<InData>
<InfoArray>
<Info>
<UnitSellPrice>100</UnitSellPrice>
</Info>
<Info>
<UnitSellPrice>324.19</UnitSellPrice>
</InfoArray>
</InData>
</Input>
XML 2:
<?xml version="1.0" encoding="UTF-8"?>
<Input>
<InData>
<InfoArray>
<Info>
<UnitSellPrice>500</UnitSellPrice>
</Info>
<Info>
<UnitSellPrice>200</UnitSellPrice>
</InfoArray>
</InData>
</Input>
错误:
Looking for function Q{http://www.w3.org/2005/xpath-functions}concat#5
Trying net.sf.saxon.functions.registry.XSLT30FunctionSet
Looking for function Q{http://www.w3.org/2005/xpath-functions}doc#1
Trying net.sf.saxon.functions.registry.XSLT30FunctionSet
Looking for function Q{http://www.w3.org/2005/xpath-functions}copy-of#1
Trying net.sf.saxon.functions.registry.XSLT30FunctionSet
Looking for function Q{http://www.w3.org/2005/xpath-functions}concat#5
Trying net.sf.saxon.functions.registry.XSLT30FunctionSet
Looking for function Q{http://www.w3.org/2005/xpath-functions}doc#1
Trying net.sf.saxon.functions.registry.XSLT30FunctionSet
Looking for function Q{http://www.w3.org/2005/xpath-functions}copy-of#1
Trying net.sf.saxon.functions.registry.XSLT30FunctionSet
java.lang.reflect.InvocationTargetException
at sun.reflect.GeneratedMethodAccessor2720.invoke(Unknown Source)
Caused by: java.lang.NullPointerException
com.saxonica.ee.stream.Streamability.getItemType(Streamability.java:267)
首先,我强烈建议您避免使用
saxon:assign
和saxon:while
。这些扩展在产品生命周期的早期就被添加到产品中,现在确实不需要它们,因为 XSLT 具有隧道参数、xsl:for-each-group
和 xsl:iterate
等结构。例如你可以写:
<xsl:template match="Input">
<xsl:for-each select="1 to $fileCount">
<xsl:variable name="fullFileName"
select="concat($inputPath,$filename,'_',.,'.xml')"/>
<out>{$fullFileName}</out>
<xsl:apply-templates
select="doc($fullFileName)/Input/InData/InfoArray/copy-of(.)"
mode="s" />
</xsl:for-each>
</xsl:template>
我实际上不知道这是否对问题有任何影响,但我很确定没有人测试过这些扩展是否在可流式样式表中工作 - 从提供的有限堆栈跟踪来看,它似乎在流动性分析,这很可能意味着
saxon:assign
和 saxon:while
的流动性分析是有缺陷的。如果是这种情况并且我们修复了它,我们几乎可以肯定地决定该指令不可流式传输。
更仔细地查看您的代码,不清楚您是如何尝试使用流式传输的。您有一个在流模式下匹配
Input
元素的模板规则,但它实际上似乎并没有使用 Input
元素中的任何数据;而辅助输入文件(使用doc()
访问)在没有流式处理的情况下进行处理。
不依赖扩展,我想你想要例如
<xsl:param name="input-uris" as="xs:string*" select="'file1.xml', 'file2.xml', 'file3.xml'"/>
然后从初始模板开始(命令行上的选项-it
,没有-s
选项;从s9api使用callTemplate(null,..)
)使用例如
<xsl:template name="xsl:initial-template">
<xsl:for-each select="$input-uris">
<xsl:source-document href="{.}" streamable="yes">
<xsl:apply-templates select="Input/InData/InfoArray/copy-of(.)" mode="s"/>
</xsl:source-document>
</xsl:for-each>
</xsl:template>