Java XPath 示例 – XPath 教程

Java XPath 示例 – XPath 教程

原文: https://howtodoinjava.com/xml/java-xpath-tutorial-example/

在此 Java XPath 教程中,我们将学习什么是 XPath 库,什么是 XPath 数据类型,并学习创建 XPath 表达式语法以从 XML 文件或文档中检索信息。 此信息可以是 XML 节点或 XML 属性,甚至可以是注释。

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。

<?xml version="1.0" encoding="utf-8" ?>
<inventory>
	<!--Test is test comment-->
		<book year="2000">
		<title>Snow Crash</title>
		<author>Neal Stephenson</author>
		<publisher>Spectra</publisher>
		<isbn>0553380958</isbn>
		<price>14.95</price>
	</book>
	<book year="2005">
		<title>Burning Tower</title>
		<author>Larry Niven</author>
		<author>Jerry Pournelle</author>
		<publisher>Pocket</publisher>
		<isbn>0743416910</isbn>
		<price>5.99</price>
	</book>
	<book year="1995">
		<title>Zodiac</title>
		<author>Neal Stephenson</author>
		<publisher>Spectra</publisher>
		<isbn>0553573862</isbn>
		<price>7.50</price>
	</book>
</inventory>

1.什么是 XPath

XPath 是一种语法,用于描述 XML 文档的各个部分。 使用 XPath,您可以引用第一个元素,元素的任何属性,包含某些文本的所有特定元素以及许多其他变体。 XSLT 样式表在匹配项中使用 XPath 表达式,并选择各种元素的属性来指示应如何转换文档。

在使用 XML 发送请求和接收响应来测试 Web 服务时,XPath 有时会很有用。

XPath 使用的语言语法与我们已经知道的非常相似。 语法是基本编程语言表达式(例如$x*6的通配符)和类 Unix 路径表达式(例如/inventory/author)的混合。

除了基本语法外,XPath 还提供了一组有用的函数(例如count()contains(),与工具函数调用非常相似),这些函数使您可以搜索文档中的各种数据片段。

2. XPath 数据模型

XPath 将 XML 文档视为节点的。 该树与文档对象模型(即 DOM 树)非常相似,因此,如果您熟悉 DOM,则可以轻松了解如何构建基本的 XPath 表达式

XPath 数据模型中有七种节点:

  1. 根节点(每个文档仅一个)
  2. 元素节点
  3. 属性节点
  4. 文本节点
  5. 注释节点
  6. 处理指令节点
  7. 命名空间节点

2.1 根节点

根节点是包含整个文档的 XPath 节点。 在我们的示例中,根节点包含<inventory>元素。 在 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 注释节点

注释节点也非常简单 - 它包含一些文本。 源文档中的每个注释都将成为注释节点。 注释节点的文本包含注释中的所有内容,除了<!--开头和-->结尾。

例如:

<!--Test is test comment-->

2.6 处理指令节点

处理指令节点具有两个部分名称(由name()函数返回)和字符串值。 字符串值是名称<?xml之后的所有内容,包括空格,但不包括关闭处理指令的?>

例如:

<?xml version="1.0" encoding="utf-8"?>

2.7 命名空间节点

XSLT 样式表几乎从未使用过命名空间节点。 它们的存在主要是为了 XSLT 处理器的利益

请记住,即使从技术上来说,命名空间的声明(例如 xmlns:auth="http://www.authors.net")在 XML 源中仍是一个属性,但它成为命名空间节点,而不是属性节点。

3. XPath 数据类型

在 Java 中,XPath 表达式可能返回以下数据类型之一:

  1. 节点集 – 表示一组节点。 该集合可以为空,也可以包含任意数量的节点。
  2. 节点 (Java 支持)– 表示单个节点。 它可以为空,也可以包含任意数量的子节点。
  3. 布尔值 – 表示值truefalse。 请注意,在 XPath 中,truefalse字符串没有特殊含义或值。 有关布尔值的更详细讨论,请参见第 4 章的 4.2.1.2 节。
  4. 数字 – 表示浮点数。 XPath 和 XSLT 中的所有数字均实现为浮点数; XPath 和 XSLT 中不存在整数(或int)数据类型。 具体来说,所有数字都实现为 IEEE 754 浮点数,与 Java floatdouble原始类型使用的标准相同。 除普通数字外,数字还有五个特殊值:正负无穷大,正负零和NaN(非数字的特殊符号)。
  5. 字符串 – 表示零个或多个字符,如 XML 规范中所定义。

这些数据类型通常很简单,并且除了节点集之外,类型之间的转换通常很简单。 我们将不在这里更详细地讨论这些数据类型。 相反,我们将讨论数据类型和转换,因为我们需要它们来执行特定的任务。

4. XPath 语法

XPath 使用 UNIX 和正则表达式这种语法。

4.1 选择具有 xpath 的节点

表达式 描述
nodename 选择所有名称为“nodename”的节点
/ 从根节点选择
// 从当前节点中选择匹配选择的节点,无论它们在何处
. 选择当前节点
.. 选择当前节点的父节点
@ 选择属性

4.2 将谓词与 xpath 一起使用

谓词用于查找特定节点或包含特定值的节点。 谓词始终嵌入在方括号中。 我们将在下一节中学习如何使用它们。

4.3 使用 xpath 访问未知节点

XPath 通配符可用于选择未知的 XML 元素。

通配符 描述
* 匹配任何元素节点
@* 匹配任何属性节点
node() 匹配任何种类的任何节点

4.4 XPath 轴

定义相对于当前节点的节点集。 以下是默认定义的轴。

轴名 结果
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 返回包含所有bookcd元素的节点集
+ 加法 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 的不同部分。

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 <title> 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 <title> 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);
	}
}

程序输出:

//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

http://en.wikipedia.org/wiki/XPath

http://oreilly.com/catalog/xmlnut/chapter/ch09.html