【问题标题】:Xalan and the document() functionXalan 和 document() 函数
【发布时间】:2014-09-04 07:38:30
【问题描述】:

由于我已经花了将近一整天的时间来调试这个,我希望对以下问题有一些有价值的见解:

我在输入文档上运行 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 属性计算得出的。我想从具有相等索引和/或子索引的外部 XML 文档加载 defaultValue 属性。 是否可以在 XPath 1.0 的谓词中使用变量?这适用于 XPath 2.0。 关于不正确的变量分配,我不再相信解析器(Xalan)问题,因为 PHP 的 XSLTProcessor 也是如此。肯定是变量声明的问题...

【问题讨论】:

  • 好吧,如果您知道 Saxon 工作正常且性能良好,那么您为什么还要为 Xalan 和 XSLT 1.0 烦恼,因为您使用的不是 JRE 中的 Xalan 版本,您无论如何都使用第三方库并且可以直接转到 Saxon 9。当然,术语 LookupElement 表明定义和使用键可能会提高性能,您需要向我们展示 XML 和myDict.xml 结构的更多细节以及它在 XSLT 中的使用。
  • @MartinHonnen 我需要维护我的样式表的 XSLT 1.0 和 2.0 版本,因为它们用于不同的环境。否则我早就放弃了 1.0 版本。我将变量直接指向包含我需要的所有数据的元素。由于这是一个直接的 XPath,我看不出有什么性能问题?
  • 我的第一个猜测是它正在从 W3C 网站加载 DTD(例如 XHTML DTD)。 W3C 人为地限制此类请求以阻止它们。但是,由于您使用的 Saxon 是一个相当旧的版本(9.1),同样的问题也会影响 Saxon,所以也许不是这样。
  • @MichaelKay 事实上,我之前找到了有关该问题的信息。外部 XML-Document 中没有引用 DTD,出于这个原因,我也删除了对其 XML-Schema 的引用。无济于事:(
  • 很难在没有看到您的输入和样式表的情况下回答。问题:如果您重组输入以使您通过 document() 读取的内容是主要的 XML 输入,那么运行需要多长时间?

标签: java xslt xpath xalan


【解决方案1】:

这只回答了问题的最后一部分,但对于 cmets 来说太笨拙了......

我有以下变量声明,当用作xsl:ifxsl:whentest 时,它总是产生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 1.0 中,具有主体而不是 select 的变量总是成为“结果树片段”,在这种情况下,单个文本节点子节点将根据需要包含字符串“true”或“false”。任何非空 RTF 在转换为布尔值时都被视为 true

在 XSLT 2.0 中也有类似的情况 - 2.0 不区分节点集和结果树片段,但变量仍将是一个“临时树”,其中包含一个文本节点子节点,其值为字符串“true”或"false",并且这两个树在转换为布尔值时都是 true。如果你想从变量中得到一个实际的布尔值,那么你需要改变两件事——将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)" />

【讨论】:

  • 这是一个很好的解释。我也不知道提到的 XPath 2.0 语法,Xpath 1.0 解决方案也比我想出的要好得多。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多