访问存储在变量中的子树会导致异常

时间:2017-02-07 10:20:41

标签: java xml xslt xslt-2.0 saxon

我正在使用Saxon HE 9.7.0来转换一些XSLT 2.0。在我的文件中,我正在尝试选择一个子树并将其放在变量中以便以后使用它。

输入XML:

<?xml version="1.0"?>
<documents>
    <document>
        <code>009190</code>
        <index>3</index>
    </document>
    <document>
        <code>583876</code>
        <index>1</index>
    </document>
    <document>
        <code>277410</code>
        <index>2</index>
    </document>
</documents>

现在在我的XSLT中,我选择索引最低的文档,并希望以后使用它的代码(变量documents包含根树):

<xsl:variable name="selectedDocument">
    <xsl:variable name="lowestDocumentIndex" select="min($documents/document/orderIndex)" />
    <xsl:value-of select="$documents/documents[index=$lowestDocumentIndex]" />
</xsl:variable>

<!-- Now later on, I want to use the contents of the selected document: -->
<xsl:value-of select="$selectedDocument/code" />

这会在解析器中导致异常,如下所示:

Caused by: java.lang.RuntimeException: Internal error evaluating template rule  at line 23 in module 
    at net.sf.saxon.expr.instruct.TemplateRule.applyLeavingTail(TemplateRule.java:366)
    at net.sf.saxon.trans.Mode.applyTemplates(Mode.java:456)
    at net.sf.saxon.Controller.transformDocument(Controller.java:2291)
    at net.sf.saxon.Controller.transform(Controller.java:1863)
    at net.sf.saxon.s9api.XsltTransformer.transform(XsltTransformer.java:579)
    at net.sf.saxon.jaxp.TransformerImpl.transform(TransformerImpl.java:185)
    at de.haba.genex.exp.core.model.nodes.XSLTTransformationNode.lambda$process$0(XSLTTransformationNode.java:146)
    ... 40 more
Caused by: java.lang.ClassCastException: net.sf.saxon.value.UntypedAtomicValue cannot be cast to net.sf.saxon.om.NodeInfo
    at net.sf.saxon.expr.SimpleStepExpression.iterate(SimpleStepExpression.java:108)
    at net.sf.saxon.expr.Atomizer.iterate(Atomizer.java:293)
    at net.sf.saxon.expr.AtomicSequenceConverter.iterate(AtomicSequenceConverter.java:249)
    at net.sf.saxon.expr.SystemFunctionCall.evaluateArguments(SystemFunctionCall.java:360)
    at net.sf.saxon.expr.FunctionCall.iterate(FunctionCall.java:544)
    at net.sf.saxon.expr.Expression.evaluateItem(Expression.java:763)
    at net.sf.saxon.expr.Expression.evaluateAsString(Expression.java:859)
    at net.sf.saxon.expr.instruct.SimpleNodeConstructor.processLeavingTail(SimpleNodeConstructor.java:186)
    at net.sf.saxon.expr.instruct.ValueOf.processLeavingTail(ValueOf.java:283)
    at net.sf.saxon.expr.instruct.Block.processLeavingTail(Block.java:653)
    at net.sf.saxon.expr.LetExpression.processLeavingTail(LetExpression.java:711)
    at net.sf.saxon.expr.instruct.Block.processLeavingTail(Block.java:653)
    at net.sf.saxon.expr.LetExpression.processLeavingTail(LetExpression.java:711)
    at net.sf.saxon.expr.instruct.Block.processLeavingTail(Block.java:653)
    at net.sf.saxon.expr.LetExpression.processLeavingTail(LetExpression.java:711)
    at net.sf.saxon.expr.instruct.Block.processLeavingTail(Block.java:653)
    at net.sf.saxon.expr.instruct.NamedTemplate.expand(NamedTemplate.java:257)
    at net.sf.saxon.expr.instruct.CallTemplate.process(CallTemplate.java:356)
    at net.sf.saxon.expr.LetExpression.process(LetExpression.java:568)
    at net.sf.saxon.expr.instruct.ForEach.processLeavingTail(ForEach.java:453)
    at net.sf.saxon.expr.LetExpression.processLeavingTail(LetExpression.java:711)
    at net.sf.saxon.expr.instruct.Choose.processLeavingTail(Choose.java:835)
    at net.sf.saxon.expr.instruct.Instruction.process(Instruction.java:149)
    at net.sf.saxon.expr.LetExpression.process(LetExpression.java:568)
    at net.sf.saxon.expr.instruct.ForEach.processLeavingTail(ForEach.java:453)
    at net.sf.saxon.expr.LetExpression.processLeavingTail(LetExpression.java:711)
    at net.sf.saxon.expr.instruct.Block.processLeavingTail(Block.java:653)
    at net.sf.saxon.expr.instruct.TemplateRule.applyLeavingTail(TemplateRule.java:353)
    ... 46 more

使用XSLT 2.0不再存储RTF但保留真正的临时树,这不应该起作用吗?

这只是我正在尝试做的一个简单示例,我实际上在<xsl:choose>中有一个<xsl:variable>并且文档结构更复杂,但这个想法应该是是一样的。

编辑:似乎我的问题与我首先将文档列表传递给另一个模板有关。使用答案中所写的xsl:copy-of似乎可行,但在我执行以下操作时则不行:

(试试http://xsltransform.net/ejivdHL/2

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:template match="/">
        <xsl:call-template name="processDocuments">
            <xsl:with-param name="docs" select="documents" />
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="processDocuments">
        <xsl:param name="docs" />

        <xsl:variable name="selectedDocument">
            <xsl:variable name="lowestDocumentIndex" select="min(doc/document/index)" />
            <xsl:copy-of select="doc/document[index=$lowestDocumentIndex]" />
        </xsl:variable>

        <xsl:value-of select="$selectedDocument/document/code" />
    </xsl:template>

</xsl:transform>

更多关于出了什么问题的想法?我需要使用第二个模板,因为我对各种节点多次使用模板。

3 个答案:

答案 0 :(得分:0)

要存储节点副本,您需要<xsl:copy-of select="$documents/documents[index=$lowestDocumentIndex]" />而不是<xsl:value-of select="$documents/documents[index=$lowestDocumentIndex]" />value-of创建一个文本节点,其中包含所选节点的字符串值。

此外,在修复我的

时,某些引用/路径似乎不匹配
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:template match="/">
        <xsl:variable name="selectedDocument">
            <xsl:variable name="lowestDocumentIndex" select="min(documents/document/index)" />
            <xsl:copy-of select="documents/document[index=$lowestDocumentIndex]" />
        </xsl:variable>

        <!-- Now later on, I want to use the contents of the selected document: -->
        <xsl:value-of select="$selectedDocument/document/code" />
    </xsl:template>

</xsl:transform>

http://xsltransform.net/ejivdHL输出583876

实际上不需要创建临时树,只需选择原始输入元素:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

    <xsl:template match="/">
        <xsl:variable name="lowestDocumentIndex" select="min(documents/document/index)" />
        <xsl:variable name="selectedDocument" select="documents/document[index=$lowestDocumentIndex]" />


        <!-- Now later on, I want to use the contents of the selected document: -->
        <xsl:value-of select="$selectedDocument/code" />
    </xsl:template>

</xsl:transform>

http://xsltransform.net/ejivdHL/1在线。

答案 1 :(得分:0)

使用:

<xsl:variable name="lowestDocumentIndex" select="min($documents/document/index)" />
<xsl:variable name="selectedDocument" select="$documents/document[index=$lowestDocumentIndex]" />

您的代码中的<xsl:value-of>似乎提取了所选节点(连接文本节点)的而不是节点本身。

顺便说一句:您的代码包含$documents/documents。 请注意,应删除最后一个s

答案 2 :(得分:0)

堆栈跟踪说&#34; Saxon内部错误&#34;意味着它是撒克逊人的虫子。可能是我们已经知道的并且可能已经修复,但是一个错误都是一样的。最好在saxonica.plan.io上的bug跟踪器上报告Saxon漏洞。我们几乎肯定需要一个&#34; repro&#34; - 即样式表和源文档,以及任何其他必要的详细信息,如配置参数,使我们能够重现问题。

只是进行一些初步分析,关键的失败是

java.lang.ClassCastException: net.sf.saxon.value.UntypedAtomicValue cannot be cast to net.sf.saxon.om.NodeInfo
at net.sf.saxon.expr.SimpleStepExpression.iterate(SimpleStepExpression.java:108)

这告诉我们这是一个运行时错误,我们正在评估一个简单的步骤表达式&#34;这类似于$ lhs / child :: X,其中LHS是返回单例的表达式,RHS是轴表达式。我可以从行号中判断出您没有执行最新的维护版本(因为转换为NodeInfo现在位于第110行)。发生ClassCastException是因为表达式的LHS应该是一个节点,但实际上是一个原子值,这意味着在类型检查中出现了错误,这应该是之前发现的。您的代码中可能存在错误,导致我们无法正确接收和诊断。

不幸的是,堆栈跟踪并没有给我们足够的信息来准确地告诉您样式表中的哪些代码在失败时正在执行。这就是我们需要repro的原因,因此我们可以在调试环境中运行它并在失败时捕获它。

这表明有两个动作:(a)请尝试最新的Saxon维护版本(目前为9.7.0.14,但请注意此空间),以及(b)如果再次崩溃,请在saxonica.plan上提交完整的复制品。 IO。谢谢!