我希望能够显示具有特定值的其他元素之间的所有元素。 例如
<wd>abc</wd>
<wd>123</wd>
<wd>456</wd>
<wd>789</wd>
<wd>def</wd>
我希望代码在abc之后和def之前查找所有单词,然后显示它们。
到目前为止我尝试的是(命名空间是ss)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ss="http://www.scansoft.com/omnipage/xml/ssdoc-schema3.xsd">
<xsl:output method="text"/>
<xsl:template match="/">
<!-- Variable declarations -->
<xsl:variable name="wds" select="//ss:wd"/>
<!-- Variable declarations end-->
<xsl:if test="preceding::ss:wd[contains(.,'7BB')">
<xsl:if test="following::ss:wd[contains(.,SHIPMENT)">
<xsl:for-each select="$wds"/>
<xsl:value-of select="$wds"/>
</xsl:if>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
但这根本不起作用。
我该如何解决这个问题?
更新:回应迈克尔
除非我忽略了某些内容,否则您的代码应该能够被复制+粘贴到我的代码中。但是,当我这样做时,XSLT会执行,但不会返回任何数据。
这就是我所拥有的:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ss="http://www.scansoft.com/omnipage/xml/ssdoc-schema3.xsd">
<xsl:template match="/">
<!-- Variable declarations -->
<xsl:variable name="wds" select="//ss:wd"/>
<!-- Variable declarations end-->
<xsl:for-each select="ss:document/ss:wd[preceding-sibling::ss:wd[.='7BB'] and following-sibling::ss:wd[.='SHIPMENT']]">
<xsl:value-of select="." />
<xsl:if test="position()!=last()">
<xsl:text>/</xsl:text>
</xsl:if>
</xsl:for-each>
Net Amount <xsl:value-of select="$wds[4]"/>
<xsl:text> </xsl:text>
VAT Amount <xsl:value-of select="$wds[8]"/>
<xsl:text> </xsl:text>
Total <xsl:value-of select="$wds[12]"/>
</xsl:template>
到目前为止,这是我的整个XSLT,我还附上了我的来源:dropbox
答案 0 :(得分:3)
这是一种在XSLT 1.0中实现目标的天真且表现不佳的方法:
/*/*[.='abc'][1]/following-sibling::*[
not(.='def' or preceding-sibling::*[.='def'])]
英文:
检索包含
abc
的第一个元素之后的所有同级元素,这些元素本身不是包含def
的元素,并且没有包含def
的前一个兄弟元素(即不包含的元素; t出现在包含def
)的元素之后。
有些人会告诉你,你永远不应该这样做。我认为他们错了。有很多情况(特别是在小数据集上),这是最简单和最明显的解决方案。还有其他情况(特别是在大型数据集上),这种方法会崩溃。
检索两个节点集(尤其是大型数据集)的交集的更好技术是 Kayessian方法。它看起来像这样:
$ns1[count(.|$ns2)=count($ns2)]
英语(非正式):
从$ ns1获取所有节点,以便将该节点添加到$ ns2不会增加其大小
从技术上讲,如果节点a
和集合$ns2
的联合创建的集合与$ns2
具有相同数量的元素,那么a
必须已经在那一套。我们希望$ns1
中的每个元素都是真的。
在我们的例子中,我们希望在包含abc
的第一个节点之后的每个兄弟节点和每个包含def
的第一个节点之前的每个兄弟节点的集合1)的交集。它看起来像这样(取决于输入的结构):
/*/*[.='abc'][1]/following-sibling::*[
count(.| /*/*[.='def'][1]/preceding-sibling::*)=
count(/*/*[.='def'][1]/preceding-sibling::*)]
以下是一个完整的例子:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:variable name="ns1" select="/*/*[.='abc'][1]/following-sibling::*" />
<xsl:variable name="ns2" select="/*/*[.='def'][1]/preceding-sibling::*" />
<xsl:template match="/">
<xsl:copy-of select="$ns1[count(.|$ns2)=count($ns2)]" />
</xsl:template>
</xsl:stylesheet>
在此输入上:
<root>
<wd>abc</wd>
<wd>123</wd>
<wd>456</wd>
<wd>789</wd>
<wd>def</wd>
</root>
你得到这个输出:
<wd>123</wd>
<wd>456</wd>
<wd>789</wd>
答案 1 :(得分:2)
这是一个非常的简单方法:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ss="http://www.scansoft.com/omnipage/xml/ssdoc-schema3.xsd">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/">
<xsl:for-each select="ss:root/ss:wd[preceding-sibling::ss:wd[.='abc'] and following-sibling::ss:wd[.='def']]">
<xsl:value-of select="." />
<xsl:if test="position()!=last()">
<xsl:text>/</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
请注意,假设输入的形式为:
<root xmlns="http://www.scansoft.com/omnipage/xml/ssdoc-schema3.xsd">
<wd>001</wd>
<wd>002</wd>
<wd>abc</wd>
<wd>123</wd>
<wd>456</wd>
<wd>789</wd>
<wd>def</wd>
<wd>998</wd>
<wd>999</wd>
</root>
根据此输入,应用上述转换的结果是:
123/456/789
您没有提供(完整)输入或所需输出,因此您需要进行必要的调整。
重要:强>
我们还假设整个节点集中只出现一次<wd>abc</wd>
和<wd>def</wd>
。否则就不那么简单了。
-
关于性能的说明:如果不在您将使用的实际处理器上进行测试,很难预测性能。一般来说,显式代码比默认代码更快:最好说ss:root/ss:wd
而不是//ss:wd
,而ss:wd
优于*
。
您链接到的文档的结构与您的问题中的示例有很大不同。具体来说,<wd l="1675" t="4243" r="1939" b="4358">7BB</wd>
节点没有以下兄弟节点,因为它是其<ln>
父节点的最后一个子节点。另请注意,值<wd>
的{{1}}会出现两次。
然而,我针对它运行了以下测试样式表:
SHIPMENT
并获得以下结果:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ss="http://www.scansoft.com/omnipage/xml/ssdoc-schema3.xsd"
exclude-result-prefixes="ss">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:template match="/">
<test>
<xsl:for-each select="//ss:wd[preceding::ss:wd[.='7BB'] and following::ss:wd[.='SHIPMENT']]">
<wd>
<xsl:value-of select="." />
</wd>
</xsl:for-each>
</test>
</xsl:template>
</xsl:stylesheet>
希望这是你可以使用的东西。
答案 2 :(得分:1)
XSLT 2.0的运算符<<
和>>
(<<
需要在XSLT样式表中写为<<
),这有助于检查文档顺序,以便{ {1}}可能会这样做。并且//ss:wd[. >> //ss:wd[. = 'abc'] and . << //ss:wd[. = 'def']]
也可以提供帮助。
您链接的XML没有for-each-group group-starting-with/group-ending-with
兄弟,元素处于更深层次。您可能想尝试是否
wd
为您提供您想要的结果,对我而言,它输出
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ss="http://www.scansoft.com/omnipage/xml/ssdoc-schema3.xsd">
<xsl:template match="/">
<!-- Variable declarations -->
<xsl:variable name="wds" select="//ss:wd"/>
<!-- Variable declarations end-->
<xsl:for-each select="$wds[preceding::ss:wd[.='7BB'] and following::ss:wd[.='SHIPMENT']]">
<xsl:value-of select="." />
<xsl:if test="position()!=last()">
<xsl:text>/</xsl:text>
</xsl:if>
</xsl:for-each>
Net Amount <xsl:value-of select="$wds[4]"/>
<xsl:text> </xsl:text>
VAT Amount <xsl:value-of select="$wds[8]"/>
<xsl:text> </xsl:text>
Total <xsl:value-of select="$wds[12]"/>
</xsl:template>
</xsl:stylesheet>