最近在手写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 文件中添加以下依赖:
二、dom4j 的使用详解
2.1 基本概念
dom4j 提供了丰富的 API 来操作 XML 文档。其核心类包括:
Document:表示整个 XML 文档。Element:表示 XML 文档中的元素节点。Attribute:表示元素的属性。SAXReader:用于读取和解析 XML 文件。
2.2 解析 XML 文件
假设有一个名为 books.xml 的 XML 文件,内容如下:
示例代码:
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
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() 返回根元素
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 对象,并添加根元素
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
// 遍历查询结果
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
示例:
// 查询所有书籍的标题
List
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 查找根元素
//(任意位置查找):
含义:在 XML 文档的任意位置查找匹配的节点,不考虑层级结构。示例://title 查找文档中所有的
[@attribute='value'](属性过滤):
含义:根据元素的属性值进行过滤。示例://book[@id='1'] 查找所有 id 属性值为 1 的
[condition](条件过滤):
含义:根据指定条件进行过滤。示例://book[title='Clean Code'] 查找所有
text()(文本节点):
含义:选择元素的文本内容。示例://book/title/text() 获取所有
具体示例:
// 1. 查找所有书籍的作者
List
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
for (Element book : javaBooks) {
System.out.println("书名: " + book.elementText("title"));
}
3.6 / 和 // 的区别详解
在 XPath 表达式中,/ 和 // 用于定义查询路径,它们的使用有显著区别:
3.6.1 /(根节点开始)
含义:从 XML 文档的根节点开始,严格按照层级结构进行匹配。
特点:
路径必须精确匹配文档的层级结构。不会跳过任何节点。
示例:
XPath 表达式 /books/book/title:
解析:尝试从根节点
XPath 表达式 /library/books/book/title:
解析:从根节点
3.6.2 //(任意位置查找)
含义:在 XML 文档的任意位置查找匹配的节点,忽略层级结构。
特点:
可以从文档的任何位置开始匹配。适用于结构复杂、层级深的 XML 文档。
示例:
XPath 表达式 //book/title:
解析:在文档的任意位置查找
3.6.3 使用场景比较
使用 /:
当 XML 文档结构已知且需要精确匹配时使用。适用于简单、层级明确的 XML 文档。
使用 //:
当 XML 文档结构复杂或层级不确定时使用。适用于需要从任意位置查找节点的场景。
3.6.4 示例比较
// 假设 XML 文档如下
/*
*/
// 使用 '/' 开始的 XPath 表达式
List
System.out.println("使用 '/' 查询结果数量: " + titles1.size()); // 输出: 0
// 使用 '//' 开始的 XPath 表达式
List
System.out.println("使用 '//' 查询结果数量: " + titles2.size()); // 输出: 1
// 输出书名
for (Element title : titles2) {
System.out.println("书名: " + title.getText());
}
四、综合使用场景总结
4.1 场景 1:解析和读取 XML 文件
利用 dom4j 读取和解析 XML 文件,提取所需的数据。例如,读取配置文件、数据交换格式等。
示例:
// 读取并打印所有书籍的信息
List
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
for (Element book : booksByJoshua) {
System.out.println("书名: " + book.elementText("title"));
}
// 查找所有书籍的标题,并按字母顺序排序
List
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 操作封装成方法或类,提高代码的复用性和可维护性。
摊牌了,不装了,整理不易,我想要你手中的关注和赞