XPath多标签选择

4

对于给定的XML,如何使用xpath选择c、d、g和h(它们将是b的子标记,而不是j)?

XML

<a>
 <b>
  <c>select me</c>
  <d>select me</d>
  <e>do not select me</e>
  <f>
    <g>select me</g>
    <h>select me</h>
  </f>
 </b>

 <j>
  <c>select me</c>
  <d>select me</d>
  <e>do not select me</e>
  <f>
    <g>select me</g>
    <h>select me</h>
  </f>
 </j>
</a>

我想使用以下代码来获取结果,但它没有给出g,h值。
xpath.compile("//a/b/*[self::c or self::d or self::f/text()");

我使用的Java代码

import org.w3c.dom.*;
import javax.xml.xpath.*;
import javax.xml.parsers.*;
import java.io.IOException;
import org.xml.sax.SAXException;

 public class XPathDemo {

   public static void main(String[] args) 
   throws ParserConfigurationException,SAXException,IOException,PathExpressionException {

   DocumentBuilderFactory domFactory = 
   DocumentBuilderFactory.newInstance();
   domFactory.setNamespaceAware(true); 
   DocumentBuilder builder = domFactory.newDocumentBuilder();
   Document doc = builder.parse("test.xml");
   XPath xpath = XPathFactory.newInstance().newXPath();

   XPathExpression expr = xpath.compile("//a/b/*[self::c or self::d or self::f]/text()");

  Object result = expr.evaluate(doc, XPathConstants.NODESET);
  NodeList nodes = (NodeList) result;
    for (int i = 0; i < nodes.getLength(); i++) {
        System.out.println(nodes.item(i).getNodeValue()); 
   }
}

有人能帮我吗?

非常感谢!!!

3个回答

9

如果您想选择所有c、d、g、h节点,请使用此xpath:

"//c|//d|//g|//h"

如果您想指定从根目录开始的完整路径,请使用此选项:

"/a/b/c|/a/b/d|/a/b/f/g|/a/b/f/h"

或者如果您想要所有在 b 内的 c、d、g 或 h:

"//b//c|//b//d|//b//g|//b//h"

此外,在您的代码中,请使用nodes.item(i).getTextContent()代替GetNodeValue。

嗨,感谢您的帮助,我编辑了问题,我只需要 b 标签内的标签...我尝试使用您的查询,但出现了一些问题,它没有给出任何结果... - Pavithra Gunasekara
我不是Java专家 - 你正在使用什么类?你能发一份可以编译的代码吗? - Petar Ivanov
请注意,XPath 中不应包含 a,因为 a 是根。这是一个与 Java 无关的断言吗?因为在 XPath 中完全错误。根是 / - Emiliano Poggi
嗯,我也是这么认为的。事实上,我不是Java专家,我在C#中测试了这个问题,当我使用/a时它没有起作用 - 所以我认为这是因为它是根目录... - Petar Ivanov
不,这可能与你在 C# 中使用的对象有关,它以 a 开头。所以你的推断是错误的。 - Emiliano Poggi

4

用途:

 //a/b/*[not(self::e or self::f)]
|
 //a/b/*/*[self::g or self::h]

如果您熟悉XML文档的结构,并且可以确定//a/b的唯一子代是g和/或h,则可以简化为:

 //a/b/*[not(self::e or self::f)]
|
 //a/b/*/*

在XPath 2.0中,这甚至可以更简单地写成:
 //a/b/(*[not(self::e or self::f)] | */*)

非常感谢Dimitre,这种方式简单多了... :) - Pavithra Gunasekara
这就是我的声望值15最终消失的地方:P!无论如何,你说得对,+1。 - Emiliano Poggi
@Paithra:不用担心!那是威望的象征;-) - Emiliano Poggi

3
我该如何使用XPath选择c、d、g、h这些标签(它们是b标签的子标签且不在j标签内)?
"/a/b//*[matches(name(),'^c$|^d$|^g$|^h$')]"

为了保持你最初的位置路径不变,XPath 1.0 应该是:
"/a/b//*[name()='c' 
  or name()='d' 
  or name()='g' 
  or name()='h']"

或者,根据您对轴的使用方式:
 "/a/b//*[self::c 
  or self::d 
  or self::g 
  or self::h]"

通过在上述位置路径中添加text(),您将获得每个相关标签的文本节点。
PS:@fiver提供的解决方案应更改为/a/b/c|/a/b/d|/a/b/f/g|/a/b/f/h

非常感谢您的帮助... 我使用了这个并解决了我的问题 XPathExpression expr = xpath.compile("//b/c | //b/d | //b/f/g |//b/f/h/text()"); - Pavithra Gunasekara

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接