Xalan和document()函数

时间:2014-07-14 11:36:47

标签: java xslt xpath xalan

由于我现在花了将近一整天的时间进行调试,所以我希望在以下问题上获得一些有价值的见解:

我在输入文档上运行XSL转换,我的样式表加载了一个外部XML文档,其中包含我需要进行一些比较的查找值。 我正在加载外部文档:

<xsl:variable name="dictionary"
    select="document('myDict.xml', document(''))/path/to/LookupElement" />

LookupElement是一个包含我需要访问的完整XML片段的元素。 在整个样式表中,各种比较表达式都在访问$dictionary。 现在,发生的事情是,使用此document()函数调用的转换需要大约12(!)分钟使用Xalan(2.7。?,最新版本,从Apache网站下载,而不是JRE中包含的版本) )。

没有document()调用的相同样式表(没有我的比较访问$dictionary中的数据)在几秒钟内完成。

使用Saxon-B 9.1.0.8的相同样式表也会在几秒钟内完成。

信息:外部文件有25MB(!),我不可能减小它的大小。 我正在使用JRE 6下的ant的xslt-Task运行转换。

我不确定这是否与上述问题有关:在我的样式表中,我有表达式来测试外部XML文档中是否存在某些属性。无论属性是否存在,这些表达式总是评估为true

<xsl:variable name="myAttExists" select="boolean($dictionary/path/to/@myAttribute)"/>

我的智慧结束了。我知道Xalan正确地读取了文档,所有引用都转到$dictionary,所以我没有多次调用document()

有人任何想法吗?

修改

我已从外部XML-Document中删除了对XML-Schema的引用,以防止Xalan或底层(Xerces)Parser的Schema-Lookup。

修改

我已经确认myAttExists总是true,即使指定了整个外部XML文档中肯定不存在的属性名称。 我甚至将上面的表达式改为:

<xsl:variable name="myAttExists" select="count($dictionary/path/to/@unknownAttribute) != 0"/>

仍然会产生true

修改

我已删除对document()函数的调用以及对$dictionary的所有引用以进行测试。这会将Xalan的转换运行时间缩短到16秒。

修改

有趣的细节:Oxygen 12.1附带的Xalan版本在几秒钟内完成加载外部XML文档。但是,它也会错误地评估属性的存在......

修改

我有以下变量声明总是产生true

<xsl:variable name="expectedDefaultValueExists">
    <xsl:choose>
        <xsl:when test="@index">
            <xsl:value-of select="boolean($dictionary/epl:Object[@index = $index]/@defaultValue)"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="boolean($dictionary/epl:Object[@index = $index]/epl:SubObject[@subIndex = $subIndex]/@defaultValue)"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:variable>

这在XSLT / XPath 1.0中是否可行? $index$subIndex是根据上下文节点的@index@subIndex属性计算得出的。我想从具有相同索引和/或subIndex的外部XML-Document加载defaultValue属性。 是否可以在XPath 1.0中的谓词中使用变量?这适用于XPath 2.0。 关于不正确的变量赋值,我不再相信解析器(Xalan)问题,因为PHP的XSLTProcessor也是如此。它必须是变量声明中的一个问题......

1 个答案:

答案 0 :(得分:1)

这只能回答问题的最后部分,但是评论过于笨拙......

  

我有以下变量声明,当用作testxsl:if的{​​{1}}时,它始终为true:

xsl:when

在XSLT 1.0中,带有正文而不是<xsl:variable name="expectedDefaultValueExists"> <xsl:choose> <xsl:when test="@index"> <xsl:value-of select="boolean($dictionary/epl:Object[@index = $index]/@defaultValue)"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="boolean($dictionary/epl:Object[@index = $index]/epl:SubObject[@subIndex = $subIndex]/@defaultValue)"/> </xsl:otherwise> </xsl:choose> </xsl:variable> 的变量总是成为&#34;结果树片段&#34;,在这种情况下,单个文本节点子节点将包含字符串&#34真&#34;或&#34;假&#34;作为适当的。转换为布尔值时,任何非空RTF都被视为 true

在XSLT 2.0中,它是一个类似的故事 - 2.0并不区分节点集和结果树片段,但变量仍然是一个临时树&#34;使用单个文本节点子节点,其值为字符串&#34; true&#34;或者&#34; false&#34;,当转换为布尔值时,这两棵树都是 true 。如果您想从变量中获取实际的布尔值,那么您需要更改两件事 - 将select添加到变量声明中并使用as="xs:boolean"而不是xsl:sequence

xsl:value-of

<xsl:variable name="expectedDefaultValueExists" as="xs:boolean"> <xsl:choose> <xsl:when test="@index"> <xsl:sequence select="boolean($dictionary/epl:Object[@index = $index]/@defaultValue)"/> </xsl:when> <xsl:otherwise> <xsl:sequence select="boolean($dictionary/epl:Object[@index = $index]/epl:SubObject[@subIndex = $subIndex]/@defaultValue)"/> </xsl:otherwise> </xsl:choose> </xsl:variable> 指令将其xsl:value-of的结果转换为字符串,并构造包含该字符串的文本节点。 select指令只是直接返回xsl:sequence中的值,无论它恰好是什么类型。

但是有更简单的方法来实现同样的目标。在XPath 2.0中,你可以直接在XPath

中构造if / then / else
select

在1.0中你需要稍微有点创意

<xsl:variable name="expectedDefaultValueExists"
   select="if (@index)
           then $dictionary/epl:Object[@index = $index]/@defaultValue
           else $dictionary/epl:Object[@index = $index]/epl:SubObject[@subIndex = $subIndex]/@defaultValue" />