杰瑞科技汇

如何用dom4j高效解析Java中的XML?

准备工作:添加 dom4j 依赖

你需要在你的 Java 项目中添加 dom4j 的依赖,如果你使用 Maven,这是最简单的方式。

如何用dom4j高效解析Java中的XML?-图1
(图片来源网络,侵删)

Maven (pom.xml)

在你的 pom.xml 文件中添加以下依赖:

<dependencies>
    <!-- dom4j 核心库 -->
    <dependency>
        <groupId>org.dom4j</groupId>
        <artifactId>dom4j</artifactId>
        <version>2.1.4</version> <!-- 建议使用较新版本 -->
    </dependency>
    <!-- dom4j 依赖的 XPath 实现 -->
    <dependency>
        <groupId>jaxen</groupId>
        <artifactId>jaxen</artifactId>
        <version>1.2.0</version>
    </dependency>
</dependencies>

如果你不使用 Maven,可以从 Maven 中央仓库 下载 dom4j-2.1.4.jarjaxen-1.2.0.jar,然后手动添加到你的项目的 classpath 中。


示例 XML 文件

为了演示,我们创建一个名为 books.xml 的示例文件。

books.xml

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
    <book category="children">
        <title lang="en">Harry Potter</title>
        <author>J.K. Rowling</author>
        <year>2005</year>
        <price>29.99</price>
    </book>
    <book category="web">
        <title lang="en">Learning XML</title>
        <author>Erik T. Ray</author>
        <year>2003</year>
        <price>39.95</price>
    </book>
    <book category="cooking">
        <title lang="en">Everyday Italian</title>
        <author>Giada De Laurentiis</author>
        <year>2005</year>
        <price>30.00</price>
    </book>
</bookstore>

核心概念和 API

在开始解析之前,了解几个核心类和接口很重要:

  • SAXReader: 这是 dom4j 的核心解析器类,它的 read() 方法可以接收一个 FileURLInputStream 对象,并返回一个 Document 对象。
  • Document: 代表整个 XML 文档的树形结构,它包含了根元素。
  • Element: 代表 XML 文档中的一个元素(节点),大部分操作都是围绕 Element 进行的。
  • Attribute: 代表元素的属性。
  • Node: ElementAttributeText 等的父接口,提供了通用的节点操作方法,如 getNodeName()getText() 等。
  • DocumentHelper: 一个工具类,用于创建 DocumentElement 等对象。

完整解析示例

下面是一个完整的 Java 程序,它读取 books.xml 文件,并打印出所有书籍的信息。

Dom4jParserDemo.java

import org.dom4j.*;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.util.List;
public class Dom4jParserDemo {
    public static void main(String[] args) {
        try {
            // 1. 创建 SAXReader 实例
            SAXReader reader = new SAXReader();
            // 2. 指定 XML 文件的路径
            File xmlFile = new File("books.xml");
            // 3. 读取 XML 文件,获取 Document 对象
            // Document 对象代表了整个 XML 文档的树形结构
            Document document = reader.read(xmlFile);
            // 4. 获取根元素
            // 根元素是 <bookstore>
            Element rootElement = document.getRootElement();
            // 5. 遍历根元素下的所有子元素
            // 使用 elementIterator("book") 可以只遍历名为 "book" 的子元素
            // 或者使用 elements("book") 获取所有 "book" 元素的列表
            List<Element> bookList = rootElement.elements("book");
            System.out.println("共找到 " + bookList.size() + " 本书:\n");
            for (Element book : bookList) {
                System.out.println("----- 开始解析一本书 -----");
                // 6. 获取元素的属性
                // <book category="children"> 中的 "category"
                String category = book.attributeValue("category");
                System.out.println("类别: " + category);
                // 7. 获取子元素的文本内容
                // <title>Harry Potter</title> 中的 "Harry Potter"
                String title = book.elementText("title");
                String author = book.elementText("author");
                String year = book.elementText("year");
                String price = book.elementText("price");
                System.out.println("标题: " + title);
                System.out.println("作者: " + author);
                System.out.println("年份: " + year);
                System.out.println("价格: " + price);
                // 8. 获取带有属性的子元素的属性值
                // <title lang="en"> 中的 "lang"
                Element titleElement = book.element("title");
                String lang = titleElement.attributeValue("lang");
                System.out.println("语言: " + lang);
                System.out.println("----- 解析一本书结束 -----\n");
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }
}

代码解析:

  1. SAXReader reader = new SAXReader();: 创建解析器。
  2. reader.read(xmlFile);: 解析 XML 文件,返回一个 Document 对象,这是整个解析过程的入口。
  3. document.getRootElement();: 获取 XML 的根节点,这里是 <bookstore>
  4. rootElement.elements("book"): 获取根节点下所有名为 book 的子元素,返回一个 List<Element>,这是遍历 XML 结构最常用的方法之一。
  5. book.attributeValue("category"): 获取当前 book 元素的 category 属性的值。
  6. book.elementText("title"): 获取当前 book 元素下名为 title 的子元素的文本内容,这是一个非常便捷的方法。
  7. book.element("title").attributeValue("lang"): 先获取 title 元素,然后调用其 attributeValue 方法来获取 lang 属性的值。

使用 XPath 进行更强大的查询

dom4j 对 XPath 提供了非常好的支持,XPath 是一种在 XML 文档中查找信息的语言,比逐层遍历更简洁、更强大。

如何使用 XPath?

通过 document.selectNodes()element.selectNodes() 可以执行 XPath 表达式,返回一个 List<Node>,通过 document.selectSingleNode()element.selectSingleNode() 可以返回单个 Node

示例:使用 XPath 查询

import org.dom4j.*;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.util.List;
public class Dom4jXPathDemo {
    public static void main(String[] args) {
        try {
            SAXReader reader = new SAXReader();
            Document document = reader.read(new File("books.xml"));
            // XPath 示例 1: 获取所有书籍的标题
            System.out.println("--- 所有书籍的标题 ---");
            List<Node> titleNodes = document.selectNodes("//book/title");
            for (Node node : titleNodes) {
                Element titleElement = (Element) node;
                System.out.println(titleElement.getText());
            }
            // XPath 示例 2: 获取所有价格大于 30 的书籍
            System.out.println("\n--- 价格大于 30 的书籍 ---");
            List<Node> expensiveBooks = document.selectNodes("//book[price > 30]");
            for (Node node : expensiveBooks) {
                Element bookElement = (Element) node;
                System.out.println("书名: " + bookElement.elementText("title") + 
                                   ", 价格: " + bookElement.elementText("price"));
            }
            // XPath 示例 3: 获取第一本书的语言属性
            System.out.println("\n--- 第一本书的语言属性 ---");
            Node firstBookLangNode = document.selectSingleNode("//book[1]/title/@lang");
            if (firstBookLangNode != null) {
                Attribute langAttribute = (Attribute) firstBookLangNode;
                System.out.println("语言: " + langAttribute.getValue());
            }
            // XPath 示例 4: 获取作者为 'J.K. Rowling' 的书籍
            System.out.println("\n--- 作者为 'J.K. Rowling' 的书籍 ---");
            List<Node> booksByAuthor = document.selectNodes("//book[author='J.K. Rowling']");
            for (Node node : booksByAuthor) {
                Element bookElement = (Element) node;
                System.out.println("书名: " + bookElement.elementText("title"));
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }
}

XPath 表达式解释:

  • //book/title: 选择所有名为 book 的元素下的所有名为 title 的元素,无论它们在文档中的位置多深。
  • //book[price > 30]: 使用谓语 [price > 30] 筛选 price 子元素的文本值大于 30 的 book 元素。
  • //book[1]/title/@lang: book[1] 选择第一个 book 元素。/title 选择其子元素 title/@lang 选择 title 元素的 lang 属性。
  • //book[author='J.K. Rowling']: 使用谓语 [author='J.K. Rowling'] 筛选 author 子元素的文本值等于 'J.K. Rowling' 的 book 元素。

修改 XML 文件

dom4j 不仅可以解析 XML,还可以创建、修改和写入 XML。

示例:修改 XML 并保存

import org.dom4j.*;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import java.io.File;
import java.io.FileOutputStream;
public class Dom4jModifyDemo {
    public static void main(String[] args) {
        try {
            SAXReader reader = new SAXReader();
            Document document = reader.read(new File("books.xml"));
            // 1. 修改现有内容
            // 找到第一本书的价格并修改
            Element firstBook = (Element) document.selectSingleNode("//book[1]");
            firstBook.element("price").setText("19.99");
            // 2. 添加新元素
            // 在第一本书中添加一个 <publisher> 元素
            Element publisher = DocumentHelper.createElement("publisher");
            publisher.setText("Bloomsbury Publishing");
            firstBook.add(publisher);
            // 3. 添加新属性
            // 给第一本书的 title 元素添加一个新属性 id="001"
            Element firstBookTitle = firstBook.element("title");
            firstBookTitle.addAttribute("id", "001");
            // 4. 删除元素
            // 删除最后一本书
            Element lastBook = (Element) document.selectSingleNode("//book[last()]");
            Element parent = lastBook.getParent();
            parent.remove(lastBook);
            // 5. 将修改后的 Document 写入文件
            // 使用 OutputFormat 可以控制输出格式,如缩进和编码
            OutputFormat format = OutputFormat.createPrettyPrint();
            format.setEncoding("UTF-8"); // 设置编码
            XMLWriter writer = new XMLWriter(new FileOutputStream(new File("books_modified.xml")), format);
            writer.write(document);
            writer.close();
            System.out.println("XML 文件修改成功,已保存为 books_modified.xml");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行后,会生成一个 books_modified.xml 文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
  <book category="children">lang="en" id="001">Harry Potter</title>
    <author>J.K. Rowling</author>
    <year>2005</year>
    <price>19.99</price>
    <publisher>Bloomsbury Publishing</publisher>
  </book>
  <book category="web">lang="en">Learning XML</title>
    <author>Erik T. Ray</author>
    <year>2003</year>
    <price>39.95</price>
  </book>
</bookstore>

功能 核心方法/代码 说明
解析 SAXReader reader = new SAXReader();
Document doc = reader.read(file);
创建解析器并读取 XML 文件,得到 Document 对象。
获取根元素 Element root = doc.getRootElement(); 获取 XML 的顶层节点。
遍历子元素 List<Element> list = root.elements("book"); 获取指定名称的直接子元素列表。
获取属性 String attrValue = element.attributeValue("name"); 获取元素的属性值。
获取文本 String text = element.elementText("title"); 获取指定子元素的文本内容。
XPath 查询 List<Node> nodes = doc.selectNodes("//book/price"); 使用 XPath 表达式高效查询节点。
修改元素 element.setText("new text"); 修改元素的文本内容。
添加元素 parentElement.addElement("newChild"); 添加一个新的子元素。
添加属性 element.addAttribute("id", "123"); 为元素添加一个新属性。
删除元素 parent.remove(child); 从父节点中移除一个子节点。
写入文件 XMLWriter writer = new XMLWriter(outputStream, format);
writer.write(document);
Document 对象写出到文件或流。

dom4j 是一个非常灵活和强大的工具,无论是简单的数据提取还是复杂的 XML 文档操作,它都能胜任,希望这份详细的教程能帮助你掌握它!

分享:
扫描分享到社交APP
上一篇
下一篇