最近在手写mybatis框架的时候,需要对xml文件进行解析,并读取其中的数据,来进行后续映射操作。对xml的文件的解析和数据获取用到了dom4j和jaxen两个库,所以系统的学习和整理一下两个库的知识点和用法。
一、dom4j
和 jaxen
依赖概述
1.1 什么是 dom4j
?
dom4j
是一个开源的、灵活的 Java XML 解析和生成库。它提供了简单易用的 API 来读取、创建、修改和遍历 XML 文档。dom4j
支持多种 XML 解析方式(如 DOM、SAX 和 JAXP),并且性能优越,适用于处理各种规模的 XML 文件。
1.2 什么是 jaxen
?
jaxen
是一个基于 Java 的 XPath 引擎,用于在 XML 文档中执行 XPath 查询(dom4j库中,相关XPath查询的方法,都是调用了jaxen库中的方法)。XPath 是一种用于在 XML 文档中定位和选取节点的语言,jaxen
提供了强大的功能来解析和执行这些查询。jaxen
通常与 dom4j
配合使用,以增强 XML 数据的检索能力。
1.3 Maven 依赖引入
要在项目中使用 dom4j
和 jaxen
,需要在 pom.xml
文件中添加以下依赖:
<dependencies>
<!-- dom4j 依赖 -->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<!-- jaxen 依赖 -->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1.6</version>
</dependency>
</dependencies>
二、dom4j
的使用详解
2.1 基本概念
dom4j
提供了丰富的 API 来操作 XML 文档。其核心类包括:
Document
:表示整个 XML 文档。Element
:表示 XML 文档中的元素节点。Attribute
:表示元素的属性。SAXReader
:用于读取和解析 XML 文件。
2.2 解析 XML 文件
假设有一个名为 books.xml
的 XML 文件,内容如下:
<books>
<book id="1">
<title>Effective Java</title>
<author>Joshua Bloch</author>
</book>
<book id="2">
<title>Clean Code</title>
<author>Robert C. Martin</author>
</book>
</books>
示例代码:
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.util.List;
public class Dom4jExample {
public static void main(String[] args) {
try {
// 创建 SAXReader 对象,读取 XML 文件
SAXReader reader = new SAXReader();
Document document = reader.read(new File("books.xml"));
// 获取根元素
Element root = document.getRootElement();
System.out.println("根元素: " + root.getName());
// 获取所有 book 元素
List<Element> books = root.elements("book");
for (Element book : books) {
String id = book.attributeValue("id");
String title = book.elementText("title");
String author = book.elementText("author");
System.out.println("书籍 ID: " + id);
System.out.println("书名: " + title);
System.out.println("作者: " + author);
System.out.println("---------------------------");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
代码解释:
- 创建
SAXReader
对象:用于读取和解析 XML 文件。 - 读取 XML 文件:
reader.read(new File("books.xml"))
将 XML 文件解析为Document
对象。 - 获取根元素:
document.getRootElement()
返回根元素<books>
。 - 遍历
book
元素:root.elements("book")
获取所有子元素<book>
,然后遍历每个book
元素,读取其属性和子元素的文本内容。
2.3 生成 XML 文件
除了解析,dom4j
还可以用于生成 XML 文件。
示例代码:
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.XMLWriter;
import java.io.FileWriter;
public class GenerateXmlExample {
public static void main(String[] args) {
try {
// 创建文档和根元素
Document document = DocumentHelper.createDocument();
Element root = document.addElement("books");
// 创建第一个 book 元素
Element book1 = root.addElement("book").addAttribute("id", "1");
book1.addElement("title").setText("Effective Java");
book1.addElement("author").setText("Joshua Bloch");
// 创建第二个 book 元素
Element book2 = root.addElement("book").addAttribute("id", "2");
book2.addElement("title").setText("Clean Code");
book2.addElement("author").setText("Robert C. Martin");
// 将文档写入文件
XMLWriter writer = new XMLWriter(new FileWriter("generatedBooks.xml"));
writer.write(document);
writer.close();
System.out.println("XML 文件生成成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
代码解释:
- 创建文档和根元素:使用
DocumentHelper.createDocument()
创建一个新的Document
对象,并添加根元素<books>
。 - 添加子元素:通过
addElement
方法添加<book>
元素,并设置其id
属性。 - 设置子元素内容:为每个
book
元素添加<title>
和<author>
子元素,并设置其文本内容。 - 写入文件:使用
XMLWriter
将生成的Document
对象写入到generatedBooks.xml
文件中。
2.4 常用方法汇总
-
读取和解析:
SAXReader.read(File file)
:读取 XML 文件并返回Document
对象。Document.getRootElement()
:获取 XML 文档的根元素。
-
操作元素:
Element.addElement(String name)
:添加一个子元素。Element.attributeValue(String name)
:获取元素的属性值。Element.elementText(String name)
:获取子元素的文本内容。Element.elements(String name)
:获取指定名称的所有子元素列表。
-
生成和写入:
DocumentHelper.createDocument()
:创建一个新的Document
对象。XMLWriter.write(Document document)
:将Document
对象写入到指定的输出流。
三、jaxen
的使用详解
3.1 XPath 概述
XPath(XML Path Language)是一种用于在 XML 文档中定位和选取节点的语言。它通过路径表达式来导航 XML 文档的层次结构,可以高效地查找特定的元素或属性。
3.2 jaxen
与 dom4j
的结合使用
jaxen
通常与 dom4j
配合使用,利用 dom4j
的 XML 解析能力和 jaxen
的 XPath 查询能力,实现强大的 XML 数据检索功能。
3.3 使用 XPath 查询 XML
继续使用前面的 books.xml
文件,演示如何使用 jaxen
进行 XPath 查询。
示例代码:
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.dom4j.xpath.XPath;
import java.io.File;
import java.util.List;
public class JaxenExample {
public static void main(String[] args) {
try {
// 创建 SAXReader 对象,读取 XML 文件
SAXReader reader = new SAXReader();
Document document = reader.read(new File("books.xml"));
// 创建 XPath 表达式,查找 title 为 "Clean Code" 的 book 元素
XPath xpath = document.createXPath("//book[title='Clean Code']");
List<Element> books = xpath.selectNodes(document);
// 遍历查询结果
for (Element book : books) {
String id = book.attributeValue("id");
String title = book.elementText("title");
String author = book.elementText("author");
System.out.println("找到的书籍 ID: " + id);
System.out.println("书名: " + title);
System.out.println("作者: " + author);
System.out.println("---------------------------");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
代码解释:
- 创建
SAXReader
对象:用于读取和解析 XML 文件。 - 读取 XML 文件:
reader.read(new File("books.xml"))
将 XML 文件解析为Document
对象。 - 创建 XPath 表达式:
//book[title='Clean Code']
表示查找所有book
元素,其子元素title
的值为"Clean Code"
。 - 执行查询:
xpath.selectNodes(document)
执行 XPath 查询,返回匹配的book
元素列表。 - 遍历结果:遍历匹配的
book
元素,读取其属性和子元素的文本内容。
3.4 selectNodes
和 selectSingleNode
方法详解
3.4.1 selectNodes()
selectNodes()
方法用于执行 XPath 查询并返回多个匹配的节点。其返回类型是 List<Element>
,包含所有符合条件的元素。
示例:
// 查询所有书籍的标题
List<Element> titles = document.selectNodes("//book/title");
for (Element title : titles) {
System.out.println("书名: " + title.getText());
}
解释:
- XPath 表达式
//book/title
查找所有book
元素下的title
元素。 - 返回所有匹配的
title
元素,并逐一输出其文本内容。
3.4.2 selectSingleNode()
selectSingleNode()
方法用于执行 XPath 查询并返回第一个匹配的节点。如果只需要一个结果,使用该方法更高效。
示例:
// 查询第一个书籍的标题
Element firstTitle = (Element) document.selectSingleNode("//book/title");
if (firstTitle != null) {
System.out.println("第一本书的书名: " + firstTitle.getText());
}
解释:
- XPath 表达式
//book/title
查找第一个匹配的title
元素。 - 返回第一个
title
元素,并输出其文本内容。
3.5 XPath 表达式常用语法
以下是一些常用的 XPath 表达式及其含义:
-
/
(根节点开始):- 含义:从 XML 文档的根节点开始查询。
- 示例:
/books/book/title
查找根元素<books>
下的所有<book>
元素的<title>
子元素。
-
//
(任意位置查找):- 含义:在 XML 文档的任意位置查找匹配的节点,不考虑层级结构。
- 示例:
//title
查找文档中所有的<title>
元素。
-
[@attribute='value']
(属性过滤):- 含义:根据元素的属性值进行过滤。
- 示例:
//book[@id='1']
查找所有id
属性值为1
的<book>
元素。
-
[condition]
(条件过滤):- 含义:根据指定条件进行过滤。
- 示例:
//book[title='Clean Code']
查找所有<book>
元素,其子元素<title>
的值为"Clean Code"
。
-
text()
(文本节点):- 含义:选择元素的文本内容。
- 示例:
//book/title/text()
获取所有<title>
元素的文本内容。
具体示例:
// 1. 查找所有书籍的作者
List<Element> authors = document.selectNodes("//book/author");
for (Element author : authors) {
System.out.println("作者: " + author.getText());
}
// 2. 查找 id 为 "2" 的书籍
Element bookWithId2 = (Element) document.selectSingleNode("//book[@id='2']");
if (bookWithId2 != null) {
System.out.println("书名: " + bookWithId2.elementText("title"));
System.out.println("作者: " + bookWithId2.elementText("author"));
}
// 3. 查找所有包含 "Java" 的书名
List<Element> javaBooks = document.selectNodes("//book[contains(title, 'Java')]");
for (Element book : javaBooks) {
System.out.println("书名: " + book.elementText("title"));
}
3.6 /
和 //
的区别详解
在 XPath 表达式中,/
和 //
用于定义查询路径,它们的使用有显著区别:
3.6.1 /
(根节点开始)
-
含义:从 XML 文档的根节点开始,严格按照层级结构进行匹配。
-
特点:
- 路径必须精确匹配文档的层级结构。
- 不会跳过任何节点。
-
示例:
<library> <books> <book id="1"> <title>Effective Java</title> <author>Joshua Bloch</author> </book> </books> </library>
XPath 表达式
/books/book/title
:- 解析:尝试从根节点
<books>
开始查找,但实际根节点是<library>
,因此无法匹配任何节点。 - 结果:无匹配结果。
XPath 表达式
/library/books/book/title
:- 解析:从根节点
<library>
开始,依次查找<books>
、<book>
和<title>
。 - 结果:匹配
<title>Effective Java</title>
。
- 解析:尝试从根节点
3.6.2 //
(任意位置查找)
-
含义:在 XML 文档的任意位置查找匹配的节点,忽略层级结构。
-
特点:
- 可以从文档的任何位置开始匹配。
- 适用于结构复杂、层级深的 XML 文档。
-
示例:
<library> <books> <book id="1"> <title>Effective Java</title> <author>Joshua Bloch</author> </book> </books> </library>
XPath 表达式
//book/title
:- 解析:在文档的任意位置查找
<book>
元素下的<title>
元素。 - 结果:匹配
<title>Effective Java</title>
。
- 解析:在文档的任意位置查找
3.6.3 使用场景比较
-
使用
/
:- 当 XML 文档结构已知且需要精确匹配时使用。
- 适用于简单、层级明确的 XML 文档。
-
使用
//
:- 当 XML 文档结构复杂或层级不确定时使用。
- 适用于需要从任意位置查找节点的场景。
3.6.4 示例比较
// 假设 XML 文档如下
/*
<library>
<books>
<book id="1">
<title>Effective Java</title>
<author>Joshua Bloch</author>
</book>
</books>
</library>
*/
// 使用 '/' 开始的 XPath 表达式
List<Element> titles1 = document.selectNodes("/books/book/title");
System.out.println("使用 '/' 查询结果数量: " + titles1.size()); // 输出: 0
// 使用 '//' 开始的 XPath 表达式
List<Element> titles2 = document.selectNodes("//book/title");
System.out.println("使用 '//' 查询结果数量: " + titles2.size()); // 输出: 1
// 输出书名
for (Element title : titles2) {
System.out.println("书名: " + title.getText());
}
四、综合使用场景总结
4.1 场景 1:解析和读取 XML 文件
利用 dom4j
读取和解析 XML 文件,提取所需的数据。例如,读取配置文件、数据交换格式等。
示例:
// 读取并打印所有书籍的信息
List<Element> books = document.selectNodes("//book");
for (Element book : books) {
String id = book.attributeValue("id");
String title = book.elementText("title");
String author = book.elementText("author");
System.out.println("ID: " + id + ", 书名: " + title + ", 作者: " + author);
}
4.2 场景 2:生成和修改 XML 文件
使用 dom4j
动态生成或修改 XML 文件,例如生成数据导出文件、动态配置文件等。
示例:
// 修改现有 XML 文件,添加一本新书
Element newBook = root.addElement("book").addAttribute("id", "3");
newBook.addElement("title").setText("Design Patterns");
newBook.addElement("author").setText("Erich Gamma, et al.");
XMLWriter writer = new XMLWriter(new FileWriter("books.xml"));
writer.write(document);
writer.close();
4.3 场景 3:使用 XPath 查询复杂 XML 数据
利用 jaxen
和 dom4j
进行复杂的 XPath 查询,快速定位和提取特定节点或属性。
示例:
// 查找所有作者为 "Joshua Bloch" 的书籍
List<Element> booksByJoshua = document.selectNodes("//book[author='Joshua Bloch']");
for (Element book : booksByJoshua) {
System.out.println("书名: " + book.elementText("title"));
}
// 查找所有书籍的标题,并按字母顺序排序
List<Element> sortedTitles = document.selectNodes("//book/title");
sortedTitles.sort((e1, e2) -> e1.getText().compareTo(e2.getText()));
for (Element title : sortedTitles) {
System.out.println("书名: " + title.getText());
}
五、总结
5.1 dom4j
的核心优势
- 灵活性高:支持多种 XML 解析方式(DOM、SAX、JAXP)。
- API 简洁:提供直观、易用的 API 进行 XML 操作。
- 性能优越:适用于处理大规模 XML 文件。
- 功能丰富:支持 XML 的读取、创建、修改和遍历。
5.2 jaxen
的核心优势
- 强大的 XPath 支持:支持多种 XPath 版本和功能强大的查询能力。
- 高效查询:能够快速定位和选取 XML 文档中的特定节点或属性。
- 易于集成:与
dom4j
无缝集成,增强 XML 数据的检索能力。
5.3 selectNodes
与 selectSingleNode
的使用建议
-
selectNodes
:- 用于需要获取多个匹配节点的场景。
- 适用于批量处理和遍历多个节点。
-
selectSingleNode
:- 用于只需要获取第一个匹配节点的场景。
- 更加高效,适用于单一结果的查询。
5.4 /
和 //
的选择
-
使用
/
:- 当 XML 文档结构已知且需要精确匹配时。
- 适用于简单、层级明确的 XML 文档。
-
使用
//
:- 当 XML 文档结构复杂或层级不确定时。
- 适用于需要从任意位置查找节点的场景。
5.5 最佳实践
- 明确需求:在选择 XPath 表达式时,明确需要匹配的节点位置和条件。
- 优化查询:尽量使用具体的 XPath 表达式,避免不必要的广泛搜索,提高查询效率。
- 处理异常:在读取和写入 XML 文件时,妥善处理可能出现的异常,确保程序稳定性。
- 封装功能:将常用的 XML 操作封装成方法或类,提高代码的复用性和可维护性。
摊牌了,不装了,整理不易,我想要你手中的关注和赞