# Java XPath 示例 – XPath 教程
> 原文: [https://howtodoinjava.com/xml/java-xpath-tutorial-example/](https://howtodoinjava.com/xml/java-xpath-tutorial-example/)
在此 **Java XPath 教程**中,我们将学习什么是 **XPath 库**,什么是 XPath 数据类型,并学习创建 XPath 表达式语法以从 XML 文件或文档中检索信息。 此信息可以是 XML 节点或 XML 属性,甚至可以是注释。
```java
Table of Contents
1\. What is XPath?
2\. XPath Data Model
3\. XPath Data Types
4\. XPath Syntax
5\. XPath Expressions
6\. Recommended reading
```
在本教程中,我们将在运行各种 **XPath 示例**时使用此 XML。
```java
Snow Crash
Neal Stephenson
Spectra
0553380958
14.95
Burning Tower
Larry Niven
Jerry Pournelle
Pocket
0743416910
5.99
Zodiac
Neal Stephenson
Spectra
0553573862
7.50
```
## 1.什么是 XPath
[**XPath**](https://en.wikipedia.org/wiki/XPath "XPath") 是一种语法,用于描述 [XML](https://en.wikipedia.org/wiki/XML "XML") 文档的各个部分。 使用 XPath,您可以引用第一个元素,元素的任何属性,包含某些文本的所有特定元素以及许多其他变体。 [XSLT](https://en.wikipedia.org/wiki/XSLT "XSLT") 样式表在匹配项中使用 XPath 表达式,并选择各种元素的属性来指示应如何转换文档。
在使用 XML 发送请求和接收响应来测试 [Web 服务](https://en.wikipedia.org/wiki/Web_service "Web services")时,XPath 有时会很有用。
XPath 使用的语言语法与我们已经知道的非常相似。 语法是基本编程语言表达式(例如`$x*6`的通配符)和**类 Unix 路径表达式**(例如`/inventory/author`)的混合。
除了基本语法外,XPath 还提供了一组有用的函数(例如`count()`或`contains()`,与实用程序函数调用非常相似),这些函数使您可以搜索文档中的各种数据片段。
## 2\. XPath 数据模型
XPath 将 XML 文档视为节点的[树](https://en.wikipedia.org/wiki/Tree_%28data_structure%29 "tree")。 该树与[文档对象模型](https://www.w3.org/DOM/ "DOM")(即 DOM 树)非常相似,因此,如果您熟悉 DOM,则可以轻松了解如何构建基本的 **XPath 表达式**。
XPath 数据模型中有七种节点:
1. 根节点(每个文档仅一个)
2. 元素节点
3. 属性节点
4. 文字节点
5. 注释节点
6. 处理指令节点
7. 命名空间节点
#### 2.1 根节点
[根节点](https://en.wikipedia.org/wiki/Root_element "root node")是包含整个文档的 XPath 节点。 在我们的示例中,根节点包含``元素。 在 XPath 表达式中,用单斜杠(`'/'`)指定根节点。
#### 2.2 元素节点
原始 XML 文档中的每个元素都由一个 XPath 元素节点表示。
例如,在下面的示例 XML 中,是元素节点。
* `book`
* `title`
* `author`
* `publisher`
* `isbn`
* `price`
#### 2.3 属性节点
元素节点至少是 XML 源文档中每个属性的一个属性节点的父级。 **这些节点用于定义有关特定元素节点**的特征。
例如,在我们的 XML 片段“ `year`”中是一个属性节点。
#### 2.4 文字节点
文本节点非常简单。 **它们包含来自元素**的文本。 如果 XML 文档中的原始文本包含实体或字符引用,则在创建 XPath 文本节点之前将其解析。
文本节点是纯净的文本。 文本节点需要包含尽可能多的文本。 *请记住,文本节点的下一个或上一个节点不能是另一个文本节点。*
例如,我们 XML 片段中的所有值都是文本节点,例如 “ `Snow Crash`”和“ `Neal Stephenson`”。
#### 2.5 注释节点
注释节点也非常简单 - 它包含一些文本。 **源文档中的每个注释都将成为注释节点**。 注释节点的文本包含注释中的所有内容,除了``结尾。
例如:
```java
```
#### 2.6 处理指令节点
**处理指令节点具有两个部分**,**名称**(由`name()`函数返回)和**字符串值**。 字符串值是名称``。
例如:
```java
```
#### 2.7 命名空间节点
XSLT 样式表几乎从未使用过命名空间节点。 **它们的存在主要是为了 XSLT 处理器的利益**。
> 请记住,即使从技术上来说,名称空间的声明(例如 `xmlns:auth="http://www.authors.net"`)在 XML 源中仍是一个属性,但它成为名称空间节点,而不是属性节点。
## 3\. XPath 数据类型
在 Java 中,XPath 表达式可能返回以下数据类型之一:
1. [**节点集**](https://docs.oracle.com/javase/1.5.0/docs/api/javax/xml/xpath/XPathConstants.html#NODESET "NODESET") – 表示一组节点。 该集合可以为空,也可以包含任意数量的节点。
2. [**节点**](https://docs.oracle.com/javase/1.5.0/docs/api/javax/xml/xpath/XPathConstants.html#NODE "NODE") (Java 支持)– 表示单个节点。 它可以为空,也可以包含任意数量的子节点。
3. [**布尔值**](https://docs.oracle.com/javase/1.5.0/docs/api/javax/xml/xpath/XPathConstants.html#BOOLEAN "BOOLEAN") – 表示值`true`或`false`。 请注意,在 XPath 中,`true`或`false`字符串没有特殊含义或值。 有关布尔值的更详细讨论,请参见第 4 章的 4.2.1.2 节。
4. [**数字**](https://docs.oracle.com/javase/1.5.0/docs/api/javax/xml/xpath/XPathConstants.html#NUMBER "NUMBER") – 表示浮点数。 XPath 和 XSLT 中的所有数字均实现为浮点数; XPath 和 XSLT 中不存在整数(或`int`)数据类型。 具体来说,所有数字都实现为 IEEE 754 浮点数,与 Java `float`和`double`原始类型使用的标准相同。 除普通数字外,数字还有五个特殊值:正负无穷大,正负零和`NaN`(非数字的特殊符号)。
5. [**字符串**](https://docs.oracle.com/javase/1.5.0/docs/api/javax/xml/xpath/XPathConstants.html#STRING "STRING") – 表示零个或多个字符,如 XML 规范中所定义。
这些数据类型通常很简单,并且除了节点集之外,类型之间的转换通常很简单。 我们将不在这里更详细地讨论这些数据类型。 相反,我们将讨论数据类型和转换,因为我们需要它们来执行特定的任务。
## 4\. XPath 语法
XPath 使用 UNIX 和[正则表达式](https://en.wikipedia.org/wiki/Regular_expression "Regular expression")这种语法。
#### 4.1 选择具有 xpath 的节点
| 表达式 | 描述 |
| --- | --- |
| `nodename` | 选择所有名称为“`nodename`”的节点 |
| `/` | 从根节点选择 |
| `//` | 从当前节点中选择匹配选择的节点,无论它们在何处 |
| `.` | 选择当前节点 |
| `..` | 选择当前节点的父节点 |
| `@` | 选择属性 |
#### 4.2 将谓词与 xpath 一起使用
**谓词用于查找特定节点或包含特定值的节点。** *谓词始终嵌入在方括号中。*
我们将在下一节中学习如何使用它们。
#### 4.3 使用 xpath 到达未知节点
**XPath 通配符**可用于选择未知的 XML 元素。
| 通配符 | 描述 |
| --- | --- |
| `*` | 匹配任何元素节点 |
| `@*` | 匹配任何属性节点 |
| `node()` | 匹配任何种类的任何节点 |
#### 4.4 XPath 轴
[轴](https://www.w3schools.com/xsl/xpath_axes.asp "xpath axis")定义相对于当前节点的节点集。 以下是默认定义的轴。
| 轴名 | 结果 |
| --- | --- |
| `ancestor` | 选择当前节点的所有祖先(父,祖父等) |
| `ancestor-or-self` | 选择当前节点的所有祖先(父,祖父等)和当前节点本身 |
| `attribute` | 选择当前节点的所有属性 |
| `child` | 选择当前节点的所有子节点 |
| `descendant` | 选择当前节点的所有后代(子代,孙代等) |
| `descendant-or-self` | 选择当前节点的所有后代(子代,孙代等)和当前节点本身 |
| `following` | 选择当前节点的结束标记之后的文档中的所有内容 |
| `following-sibling` | 选择当前节点之后的所有同级 |
| `namespace` | 选择当前节点的所有名称空间节点 |
| `parent` | 选择当前节点的父节点 |
| `preceding` | 选择出现在文档中当前节点之前的所有节点,但祖先,属性节点和名称空间节点除外 |
| `preceding-sibling` | 选择当前节点之前的所有同级 |
| `self` | 选择当前节点 |
#### 4.5 XPath 运算符
以下是可在 XPath 表达式中使用的 **xpath 运算符**的列表:
| 运算符 | 描述 | 例 | 返回值 |
| --- | --- | --- | --- |
| |
| 计算两个节点集 | //book | //cd
| 返回包含所有`book`和`cd`元素的节点集 |
| `+` | 加法 | `6 + 4` | 10 |
| `-` | 减法 | `6 – 4` | 2 |
| `*` | 乘法 | `6 * 4` | 24 |
| `div` | 除法 | `8 div 4` | 2 |
| `=` | 等于 | `price = 9.80` | 如果价格为 9.80,则为`true`,如果价格为 9.90,则为`false` |
| `!=` | 不等于 | `price != 9.80` | 如果价格为 9.90,则为`true`,如果价格为 9.80,则为`false` |
| `<` | 小于 | `price < 9.80` | 如果价格为 9.00,则为`true`,如果价格为 9.80,则为`false` |
| `< =` | 小于或等于 | `price <= 9.80` | 如果价格为 9.00,则为`true`,如果价格为 9.90,则为`false` |
| `>` | 大于 | `prcie > 9.80` | 如果价格为 9.90,则为`true`,如果价格为 9.80,则为`false` |
| `>=` | 大于或等于 | `price >= 9.80` | 如果价格为 9.90,则为`true`,如果价格为 9.70,则为`false` |
| `or` | 或 | `price = 9.80 or price = 9.70` | 如果价格为 9.80,则为`true`,如果价格为 9.50,则为`false` |
| `and` | 且 | `price > 9.00 and price < 9.90` | 如果价格为 9.80,则为`true`,如果价格为 8.50,则为`false` |
| `mod` | 模数(除法余数) | `5 mod 2` | 1 |
## 5\. XPath 表达式
让我们尝试使用 XPath 表达式和给定的数据类型来检索 XML 的不同部分。
```java
package xml;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
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.NodeList;
public class XPathTest
{
public static void main(String[] args) throws Exception
{
//Build DOM
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true); // never forget this!
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse("inventory.xml");
//Create XPath
XPathFactory xpathfactory = XPathFactory.newInstance();
XPath xpath = xpathfactory.newXPath();
System.out.println("n//1) Get book titles written after 2001");
// 1) Get book titles written after 2001
XPathExpression expr = xpath.compile("//book[@year>2001]/title/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());
}
System.out.println("n//2) Get book titles written before 2001");
// 2) Get book titles written before 2001
expr = xpath.compile("//book[@year<2001]/title/text()");
result = expr.evaluate(doc, XPathConstants.NODESET);
nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
System.out.println("n//3) Get book titles cheaper than 8 dollars");
// 3) Get book titles cheaper than 8 dollars
expr = xpath.compile("//book[price<8]/title/text()");
result = expr.evaluate(doc, XPathConstants.NODESET);
nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
System.out.println("n//4) Get book titles costlier than 8 dollars");
// 4) Get book titles costlier than 8 dollars
expr = xpath.compile("//book[price>8]/title/text()");
result = expr.evaluate(doc, XPathConstants.NODESET);
nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
System.out.println("n//5) Get book titles added in first node");
// 5) Get book titles added in first node
expr = xpath.compile("//book[1]/title/text()");
result = expr.evaluate(doc, XPathConstants.NODESET);
nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
System.out.println("n//6) Get book title added in last node");
// 6) Get book title added in last node
expr = xpath.compile("//book[last()]/title/text()");
result = expr.evaluate(doc, XPathConstants.NODESET);
nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
System.out.println("n//7) Get all writers");
// 7) Get all writers
expr = xpath.compile("//book/author/text()");
result = expr.evaluate(doc, XPathConstants.NODESET);
nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
System.out.println("n//8) Count all books titles ");
// 8) Count all books titles
expr = xpath.compile("count(//book/title)");
result = expr.evaluate(doc, XPathConstants.NUMBER);
Double count = (Double) result;
System.out.println(count.intValue());
System.out.println("n//9) Get book titles with writer name start with Neal");
// 9) Get book titles with writer name start with Neal
expr = xpath.compile("//book[starts-with(author,'Neal')]");
result = expr.evaluate(doc, XPathConstants.NODESET);
nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i)
.getChildNodes()
.item(1) //node is on first index
.getTextContent());
}
System.out.println("n//10) Get book titles with writer name containing Niven");
// 10) Get book titles with writer name containing Niven
expr = xpath.compile("//book[contains(author,'Niven')]");
result = expr.evaluate(doc, XPathConstants.NODESET);
nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i)
.getChildNodes()
.item(1) //node is on first index
.getTextContent());
}
System.out.println("//11) Get book titles written by Neal Stephenson");
// 11) Get book titles written by Neal Stephenson
expr = xpath.compile("//book[author='Neal Stephenson']/title/text()");
result = expr.evaluate(doc, XPathConstants.NODESET);
nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
System.out.println("n//12) Get count of book titles written by Neal Stephenson");
// 12) Get count of book titles written by Neal Stephenson
expr = xpath.compile("count(//book[author='Neal Stephenson'])");
result = expr.evaluate(doc, XPathConstants.NUMBER);
count = (Double) result;
System.out.println(count.intValue());
System.out.println("n//13) Reading comment node ");
// 13) Reading comment node
expr = xpath.compile("//inventory/comment()");
result = expr.evaluate(doc, XPathConstants.STRING);
String comment = (String) result;
System.out.println(comment);
}
}
```
程序输出:
```java
//1) Get book titles written after 2001
Burning Tower
//2) Get book titles written before 2001
Snow Crash
Zodiac
//3) Get book titles cheaper than 8 dollars
Burning Tower
Zodiac
//4) Get book titles costlier than 8 dollars
Snow Crash
//5) Get book titles added in the first node
Snow Crash
//6) Get book title added in last node
Zodiac
//7) Get all writers
Neal Stephenson
Larry Niven
Jerry Pournelle
Neal Stephenson
//8) Count all books titles
3
//9) Get book titles with writer name start with Neal
Snow Crash
Zodiac
//10) Get book titles with writer name containing Niven
Burning Tower
//11) Get book titles written by Neal Stephenson
Snow Crash
Zodiac
//12) Get count of book titles written by Neal Stephenson
2
//13) Reading comment node
Test is test comment
```
希望本 xpath 教程对您有所帮助。 它将帮助您使用 Java 执行 **xpath**。 字符串的 **Java xpath 示例**也将在 **Java8** 中成功运行。
如果您有任何建议,请发表评论。
学习愉快!
推荐阅读:
[http://www.w3.org/TR/xpath-full-text-10-use-cases](https://www.w3.org/TR/xpath-full-text-10-use-cases/ "xpath use cases")
[http://en.wikipedia.org/wiki/XPath](https://en.wikipedia.org/wiki/XPath "wiki link")
[http://oreilly.com/catalog/xmlnut/chapter/ch09.html](https://oreilly.com/catalog/xmlnut/chapter/ch09.html)