我正在尝试写一个XPath表达式,将所有兄弟节点返回到一个,满足特定条件。在我的特定情况下,我有一个(X)HTML列表,其中列表项有一些具有特定的类和其他没有类的元素。
要想象: 我站在其中一个列有“foo”类的列表项(例如包含文本“D”的li,我想得到一个包含“E”,“F”和“G”的后续列表,但没有后续项目包含“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。
注意:我已经广泛搜索了一个解决方案,我知道有很多非常相似的示例,即使是在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提供的表达式让上述程序在sample.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
希望这次我能让自己更清楚......
微米。
答案 0 :(得分:3)
鉴于此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>
li
@class="foo"
。
以下是根据此新条件启动的上述XPath:
//li[@class='foo'][2]/following-sibling::li[@class='foo'][1]/preceding-sibling::li[preceding-sibling::li[@class='foo'][2]]
选择&#34; E&#34;,&#34; F&#34;和&#34; G&#34; li
元素已按要求提供。
答案 1 :(得分:0)
我试图记住我的所有XPath 1.0编程技巧,并且我已经得出结论,它不能在单个XPath 1.0表达式中完成。这是一个大胆的陈述,有人可能证明我错了。
但是,既然您使用的是Java,那么您并不局限于XPath 1.0。获得一个XPath 2.0库(例如Saxon),然后就可以编写
了for $N in following-sibling::li[@class='foo'][1]
return following-sibling::li[. << $N]
或者,既然您正在使用DOM(为什么现在有人使用DOM?)只需迭代Java代码中的以下兄弟,直到找到匹配的那个。