Java 标准库自 JDK 5.0 开始就内置了对 XPath 的支持,主要位于 javax.xml.xpath 包中。

准备工作:XML 文件
我们先准备一个示例 XML 文件 books.xml,后续所有的示例都将基于这个文件。
books.xml
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book category="FICTION">
<title lang="en">Great Gatsby</title>
<author>F. Scott Fitzgerald</author>
<year>1925</year>
<price>10.99</price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J.K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="WEB">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
核心步骤
使用 Java XPath 解析 XML 通常遵循以下四个核心步骤:
- 获取 XPathFactory 实例:这是所有 XPath 操作的入口点。
- 创建 XPath 对象:通过工厂对象创建一个 XPath 实例。
- 编译 XPath 表达式:将你的 XPath 查询字符串编译成一个
XPathExpression对象,这样可以提高重复查询的效率。 - 评估表达式并获取结果:使用
XPathExpression对象去解析 XML 文档(如Document、InputSource等)并获取结果。
代码实现示例
下面我们通过一个完整的 Java 类来演示如何执行各种 XPath 查询。

XPathParser.java
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.*;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
import java.io.File;
public class XPathParser {
public static void main(String[] args) {
try {
// 1. 创建 XPathFactory 和 XPath 对象
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xpath = xPathFactory.newXPath();
// 2. 加载 XML 文档
// DocumentBuilderFactory 用于将 XML 文件解析为 DOM 对象
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(new File("books.xml"));
// 设置为不忽略空白节点,这对于精确匹配很重要
doc.getDocumentElement().normalize();
System.out.println("--- 示例 1: 获取所有书名 ---");
// 3. 编译 XPath 表达式
XPathExpression expr = xpath.compile("//book/title/text()");
// 4. 评估表达式,获取结果
NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println("书名: " + nodes.item(i).getNodeValue());
}
System.out.println("\n--- 示例 2: 获取第一本书的作者 ---");
expr = xpath.compile("/bookstore/book[1]/author/text()");
String author = (String) expr.evaluate(doc, XPathConstants.STRING);
System.out.println("作者: " + author);
System.out.println("\n--- 示例 3: 获取类别为 'WEB' 的书的价格 ---");
expr = xpath.compile("//book[@category='WEB']/price/text()");
String price = (String) expr.evaluate(doc, XPathConstants.STRING);
System.out.println("价格: " + price);
System.out.println("\n--- 示例 4: 获取所有书的属性(节点本身) ---");
expr = xpath.compile("//book");
NodeList bookNodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < bookNodes.getLength(); i++) {
Node bookNode = bookNodes.item(i);
// 获取节点的属性
NamedNodeMap attributes = bookNode.getAttributes();
Node categoryAttr = attributes.getNamedItem("category");
System.out.println("书的类别: " + categoryAttr.getNodeValue());
// 遍历子节点获取更多信息
NodeList childNodes = bookNode.getChildNodes();
for (int j = 0; j < childNodes.getLength(); j++) {
Node child = childNodes.item(j);
if (child.getNodeType() == Node.ELEMENT_NODE) {
System.out.println(" " + child.getNodeName() + ": " + child.getTextContent());
}
}
System.out.println("----------------------");
}
System.out.println("\n--- 示例 5: 使用函数计算书的总数 ---");
expr = xpath.compile("count(//book)");
double bookCount = (Double) expr.evaluate(doc, XPathConstants.NUMBER);
System.out.println("书的总数: " + (int) bookCount);
} catch (Exception e) {
e.printStackTrace();
}
}
}
代码解析
- 加载 XML:我们使用
javax.xml.parsers.DocumentBuilder将books.xml文件解析成一个org.w3c.dom.Document对象。Document对象是内存中 XML 文档的树形表示,是 XPath 操作的基础。 xpath.compile():将字符串形式的 XPath 查询(如"//book/title/text()")编译成一个XPathExpression对象,编译后的表达式可以被多次重用,效率更高。expr.evaluate():这是执行查询的核心方法。- 第一个参数
doc是要查询的 XML 源(在这里是Document对象)。 - 第二个参数
XPathConstants指定了你期望的返回类型,常用的类型有:XPathConstants.NODESET:返回一个NodeList,通常用于匹配多个节点(如//book)。XPathConstants.NODE:返回一个单独的Node。XPathConstants.STRING:返回匹配节点的字符串值(通常是文本内容)。XPathConstants.NUMBER:返回数字(如使用count()函数)。XPathConstants.BOOLEAN:返回布尔值。
- 第一个参数
- 处理结果:
- 如果返回类型是
NODESET,我们会得到一个NodeList,然后遍历它来访问每个节点。 - 如果返回类型是
STRING,我们直接强制类型转换即可。 - 对于单个节点,我们可以调用
getNodeValue()获取其值,或者getTextContent()获取其包含的所有文本内容(包括子节点的文本)。getAttributes()用于获取节点的属性。
- 如果返回类型是
常用 XPath 表达式速查表
| XPath 表达式 | 描述 | 示例 (针对 books.xml) |
|---|---|---|
nodename |
选取此节点的所有直接子节点 | /bookstore 选取根节点的子节点 bookstore |
| 从根节点选取 | /bookstore 选取根元素 bookstore |
|
| 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置 | //book 选取所有 book 元素,无论它们在文档中的哪个位置 |
|
| 选取当前节点 | ./book 选取当前节点的直接子节点 book |
|
| 选取当前节点的父节点 | ../price 选取当前节点的父节点的 price 节点 |
|
| 选取属性 | //book[@category] 选取所有拥有 category 属性的 book 元素 |
|
text() |
选取文本节点 | //title/text() 选取所有 title 元素的文本内容 |
| 匹配任何元素节点 | bookstore/* 选取 bookstore 的所有子元素 |
|
| 匹配任何属性节点 | //book/@* 选取所有 book 元素的所有属性 |
|
[] |
用于谓词,用来查找某个特定的节点或包含某个值的节点 | /bookstore/book[1] 选取第一个 book 元素//book[@category='WEB'] 选取所有 category 属性为 WEB 的 book 元素 |
| 选择多个路径 | //book/title | //book/author 选取所有的 title 和 author 元素 |
|
count() |
计算节点数量 | count(//book) 计算所有 book 元素的数量 |
使用 InputSource 直接解析字符串或URL
除了从文件加载,你还可以直接从字符串或 URL 加载 XML。
import javax.xml.xpath.*; import org.xml.sax.InputSource; // ... 其他代码 ... // 从字符串加载 XML String xmlString = "<root><item>hello</item></root>"; InputSource sourceFromString = new InputSource(new StringReader(xmlString)); // 使用 xpath.evaluate(sourceFromString, ...) 进行查询 // 从 URL 加载 XML String urlString = "http://example.com/data.xml"; InputSource sourceFromUrl = new InputSource(urlString); // 使用 xpath.evaluate(sourceFromUrl, ...) 进行查询
Java 内置的 XPath 功能非常强大且易于使用,尤其适合处理已经加载到内存中的 DOM 文档,对于更复杂的 XML 处理需求,你还可以结合其他 XML API,如 SAX(用于流式解析,节省内存)或 StAX(也用于流式解析,性能更高)。
希望这份详细的指南能帮助你掌握 Java 中使用 XPath 解析 XML 的技能!

