Java中对xml文件解析并获取数据的方法——dom4j库和jaxen库的用法解读
最近在手写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 操作封装成方法或类,提高代码的复用性和可维护性。
摊牌了,不装了,整理不易,我想要你手中的关注和赞
