ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
# 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 <?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**](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 节点。 在我们的示例中,根节点包含`<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 注释节点 注释节点也非常简单 - 它包含一些文本。 **源文档中的每个注释都将成为注释节点**。 注释节点的文本包含注释中的所有内容,除了`<!--`开头和`-->`结尾。 例如: ```java <!--Test is test comment--> ``` #### 2.6 处理指令节点 **处理指令节点具有两个部分**,**名称**(由`name()`函数返回)和**字符串值**。 字符串值是名称`<?xml`之后的所有内容,包括空格,但不包括关闭处理指令的`?>`。 例如: ```java <?xml version="1.0" encoding="utf-8"?> ``` #### 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 运算符**的列表: | 运算符 | 描述 | 例 | 返回值 | | --- | --- | --- | --- | | <code>&#124;</code> | 计算两个节点集 | <code>//book &#124; //cd</code> | 返回包含所有`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 <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); } } ``` 程序输出: ```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)