java - Xalan 和 document() 函数

标签 java xslt xpath xalan

由于我现在花了几乎一整天的时间来调试这个问题,我希望能够对以下问题获得一些有值(value)的见解:

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

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

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

没有 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 文档中删除了对 XML 架构的引用,以防止对 Xalan 或底层 (Xerces) 解析器进行架构查找。

编辑:

我已经验证 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 文档加载 defaultValue 属性。 是否可以在 XPath 1.0 的谓词中使用变量?这适用于 XPath 2.0。 关于不正确的变量分配,我不再相信解析器(Xalan)问题,因为 PHP 的 XSLTProcessor 也是这样做的。肯定是变量声明的问题...

最佳答案

这仅回答了问题的最后一部分,但它对于评论来说太笨拙了......

I have the following variable declaration which always yields true when used as the test of an xsl:if or xsl:when:

<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 1.0 中,具有主体而不是 select 的变量始终成为“结果树片段”,在本例中,具有单个文本节点子节点,该子节点将根据需要包含字符串“true”或“false”。任何非空 RTF 在转换为 boolean 值时都被视为true

在 XSLT 2.0 中,这是一个类似的故事 - 2.0 不区分节点集和结果树片段,但变量仍然是一个“临时树”,具有单个文本节点子节点,其值为字符串“true”或“false”,并且当转换为 boolean 值时,这两个树都是true。如果您想从变量中获取实际的 boolean 值,那么您需要更改两件事 - 将 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 指令只是直接从 select 返回值,无论它是什么类型。

但是有更简单的方法可以实现同样的目的。在 XPath 2.0 中,您可以直接在 XPath 中执行 if/then/else 构造

<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" />

在 1.0 中,你需要更有创意

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

关于java - Xalan 和 document() 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24735667/

相关文章:

java - 用 Red5 创造虚拟世界

java - 托管一个基于java的服务器

xml - xslt 1.0 - 如何使用相同级别的元素进行嵌套分组

jquery - xpath:是否可以排除 not 函数中的最后一个元素

java - 在 HashMap 实现中调整数组表的大小

java - 存储 ArrayList 中的重叠日期

java - dyn :evaluate extension function known to have issues in Xalan-J 2. 7.1 是吗?

xslt - 在 icecast 服务器的 xslt 实现中检测 node-set() 函数的可用性

xml - 如何通过Jenkins API查询特定资源?

xml - 如何处理 XQuery 中的递归?