gpt4 book ai didi

java - XPath:如何选择满足某些条件的所有兄弟节点?

转载 作者:行者123 更新时间:2023-12-01 22:26:20 24 4
gpt4 key购买 nike

我正在尝试编写一个 XPath 表达式,将所有兄弟节点返回到一个,满足特定条件。在我的具体情况下,我有一个 (X)HTML 列表,其中包含一些列表项,其中一些具有特定的类,而其他元素则没有类。

可视化:我正站在确实具有“foo”类的列表项之一(例如包含文本“D”的 li,我想获取包含“E”、“F”和“G”的后续 li 的列表,但后续项目均不包含“H”、“I”和“J”。

...
<li class="foo">A</li>
<li>B</li>
<li>C</li>
<li class="foo">D</li>
<li>E</li>
<li>F</li>
<li>G</li>
<li class="foo">H</li>
<li>I</li>
<li>J</li>
...

我正站在确实有类“foo”的列表项之一(例如包含文本“D”的li,我想获取包含“E”、“F”和的后续li的列表“G”,但后续项目均不包含“H”、“I”和“J”。

我正在使用 Java v1.8 及其内置 javax.xml.xpath 包访问先前解析的 org.w3c.dom.Document。

注意:我在 google 上广泛搜索了一个解决方案,我知道有很多看起来非常相似的示例,甚至在 StackOverflow 上也是如此,但这些都不适合我!无论我尝试并适应手头的情况,总是只给我第一个元素(在本例中为“E”)或根本不给我。 :-(

稍后添加:

由于我显然表达得如此糟糕,所以我附加了一个测试程序:

package pull_lis;

import java.io.FileInputStream;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.tidy.Tidy;

public class TestXPathExpression
{
public static void main(String[] args) throws Exception {
Tidy tidy = new Tidy();
XPathFactory xpathfactory = XPathFactory.newInstance();
XPath xpath = xpathfactory.newXPath();

Document doc = tidy.parseDOM(new FileInputStream("sample.xml"), System.out);

XPathExpression expr1 = xpath.compile("//li[@class='foo']");

// XPathExpression expr2 = xpath.compile("//li[@class='foo'][2]/following-sibling::li[@class='foo'][1]/preceding-sibling::li[preceding-sibling::li[@class='foo'][2]]");
XPathExpression expr2 = xpath.compile("???"); // <<<< IT IS THIS EXPRESSION THAT I AM SEEKING

NodeList foos = (NodeList)expr1.evaluate(doc, XPathConstants.NODESET);
System.out.println(foos.getLength() + " foos found.");

for (int idx1 = 0; idx1 < foos.getLength(); idx1++) {
Node foo = foos.item(idx1);
System.out.println("foo[" + idx1 + "]: " + foo.getChildNodes().item(0).getNodeValue());
NodeList nodes = (NodeList)expr2.evaluate(foo, XPathConstants.NODESET);
for (int idx2 = 0; idx2 < nodes.getLength(); idx2++) {
Node node = nodes.item(idx2);
System.out.println(non-foo[" + idx2 + "]: " + node.getChildNodes().item(0).getNodeValue());
}
}
}
}

sample.xml 包含:

<html>
<head>
<title>Example</title>
</head>
<body>
<ul>
<li class="foo">A</li>
<li>B</li>
<li>C</li>
<li class="foo">D</li>
<li>E</li>
<li>F</li>
<li>G</li>
<li class="foo">H</li>
<li>I</li>
<li>J</li>
</ul>
</body>
</html>

如果我使用 kjhughes 提供的表达式让上述程序在 example.xml 上运行,我会得到:

3 foos found.
foo[0]: A
non-foo[0]: E
non-foo[1]: F
non-foo[2]: G
foo[1]: D
non-foo[0]: E
non-foo[1]: F
non-foo[2]: G
foo[2]: H
non-foo[0]: E
non-foo[1]: F
non-foo[2]: G

但我想要/需要的是:

3 foos found.
foo[0]: A
non-foo[0]: B
non-foo[1]: C
foo[1]: D
non-foo[0]: E
non-foo[1]: F
non-foo[2]: G
foo[2]: H
non-foo[0]: I
non-foo[1]: J

希望这次我能说得更清楚一点......

M.

最佳答案

鉴于此 XHTML:

<ul>
<li class="foo">A</li>
<li>B</li>
<li>C</li>
<li class="foo">D</li>
<li>E</li>
<li>F</li>
<li>G</li>
<li class="foo">H</li>
<li>I</li>
<li>J</li>
</ul>

此 XPath:

//li[. = 'D']/following-sibling::li[@class='foo'][1]/preceding-sibling::li[preceding-sibling::li[. = 'D']]

将返回那些 li启动后<li>D</li>但在下一个li之前与 class='foo' :

<li>E</li>
<li>F</li>
<li>G</li>
<小时/>

更新

OP 在评论中指出,第一个感兴趣的节点不应由其“D”内容来标记,而应由第二个 li 来标记。与 @class="foo" .

以下是根据此新标准启动的上述 XPath:

//li[@class='foo'][2]/following-sibling::li[@class='foo'][1]/preceding-sibling::li[preceding-sibling::li[@class='foo'][2]]

它选择“E”、“F”和“G”li根据要求的元素。

关于java - XPath:如何选择满足某些条件的所有兄弟节点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28709046/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com