我有一个类似于以下内容的HTML / XML文档。在以任意重复的图案切换到另一种颜色之前,可以存在一个或多个相同颜色的“tr”。这是一个例子:
<tr class='red'></tr>
<tr class='blue'></tr>
<tr class='red'></tr>
<tr class='red'></tr>
<tr class='red'></tr>
<tr class='blue'></tr>
<tr class='blue'></tr>
<tr class='red'></tr>
<tr class='red'></tr>
<tr class='blue'></tr>
我正在寻找的是一个XPath(1.0)表达式,从任何颜色“块”中的第一个“tr”开始(请注意,没有标记表示这些块,只有更改在颜色中),仅在该块中选择以下后续'tr。
我尝试过以下表达式
./following-sibling::tr[@class=preceding-sibling::tr[1]/@class]
但这也选择后续块的第二个+'tr。我觉得我接近我需要的东西,但不能完全控制它。
提前致谢。
编辑:所需的输出是一个节点集,其中包含块中的后续'tr'(仅限该块)。
答案 0 :(得分:3)
此XPath 1.0表达式选择蓝色tr
元素的第一个“块”:
(/*/tr[@class='blue'][1] | /*/tr[@class='blue'][1]/following-sibling::tr)
[count(. | /*/tr[@class='blue'][1]
/following-sibling::tr
[not(@class='blue')][1]
/preceding-sibling::*
)
=
count(/*/tr[@class='blue'][1]
/following-sibling::tr
[not(@class='blue')][1]
/preceding-sibling::*
)
]
<强>解释:
使用众所周知的 Kayessian公式进行节点集交集:
$ns1[count(.|$ns2) = count($ns2)]
此XPath表达式精确选择属于节点集$ns1
和节点集$ns2
的节点。
在这种特殊情况下,我们只需将$ns1
和$ns2
替换为适当的特定XPath表达式 - 一个是第一个蓝色tr
及其所有后续兄弟,另一个是在第一个蓝色tr
及其所有前面的兄弟姐妹之后的第一个非蓝色tr
。这两个节点集的交集正好是蓝色tr
s的所需第一个块。
基于XSLT的验证:
<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:template match="node()|@*">
<xsl:copy-of select=
"(/*/tr[@class='blue'][1] | /*/tr[@class='blue'][1]/following-sibling::tr)
[count(. | /*/tr[@class='blue'][1]
/following-sibling::tr
[not(@class='blue')][1]
/preceding-sibling::*
)
=
count(/*/tr[@class='blue'][1]
/following-sibling::tr
[not(@class='blue')][1]
/preceding-sibling::*
)
]
"/>
</xsl:template>
</xsl:stylesheet>
将此转换应用于以下XML文档时:
<t>
<tr class='red'></tr>
<tr class='red'></tr>
<tr class='red'></tr>
<tr class='red'></tr>
<tr class='blue'></tr>
<tr class='blue'></tr>
<tr class='red'></tr>
<tr class='red'></tr>
<tr class='blue'></tr>
</t>
评估XPath表达式并将选定的节点复制到输出中:
<tr class="blue"/>
<tr class="blue"/>
答案 1 :(得分:0)
如果你有一个变量$ v绑定到起始节点,那么我认为它可以完成(具有可怕的低效率),如下所示:
$v/following-sibling::tr[@class = $v/@class and count(preceding-sibling::tr[not(@class=$v/@class)] = count($v/preceding-sibling::tr[not(@class=$v/@class)])]
如果您的API没有给您绑定变量的机会,那么我认为不能这样做,尽管我愿意被证明是错误的。
您还没有说出您的约束条件,但XPath 1.0对于此特定问题似乎不是一个很好的技术选择。
即使在XPath 2.0中,它也不是特别好。你真的需要递归,这意味着使用XQuery或XSLT而不是纯XPath。