由于我现在花了几乎一整天的时间来调试这个问题,我希望能够对以下问题获得一些有值(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 anxsl:if
orxsl: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/