杰瑞科技汇

dom4j如何将XML转为Java对象?

我们需要结合 dom4jXStream(或 JAXB 等其他库)来完成这个任务,XStream 是一个专门用于对象和 XML 之间相互转换的库,它非常灵活且易于使用。

dom4j如何将XML转为Java对象?-图1
(图片来源网络,侵删)

下面我将为你提供一个完整的、分步的教程,展示如何使用 dom4j + XStream 来实现这个目标。


推荐使用 XStream (最简单、最常用)

XStream 的核心思想是将 Java 对象的字段名与 XML 的标签名进行映射,从而实现自动转换。

第 1 步:添加 Maven 依赖

在你的 pom.xml 文件中添加 dom4j 和 XStream 的依赖。

<dependencies>
    <!-- dom4j 用于解析 XML -->
    <dependency>
        <groupId>org.dom4j</groupId>
        <artifactId>dom4j</artifactId>
        <version>2.1.4</version>
    </dependency>
    <!-- XStream 用于 Java 对象和 XML 的相互转换 -->
    <dependency>
        <groupId>com.thoughtworks.xstream</groupId>
        <artifactId>xstream</artifactId>
        <version>1.4.20</version>
    </dependency>
    <!-- XStream 需要 dom4j 或其他 XML 解析器,JDK 自带的 StAX 也可以,但 dom4j 是更常见的选择 -->
    <!-- 如果使用 JDK 9+,可能需要添加这个依赖来访问 JAXB 模块 -->
    <!--
    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.3.1</version>
    </dependency>
    -->
</dependencies>

第 2 步:创建 Java 实体类

创建一个与你的 XML 结构相匹配的 Java 类,XStream 会通过反射来访问这个类的字段。

dom4j如何将XML转为Java对象?-图2
(图片来源网络,侵删)

假设我们有如下的 student.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<students>
    <student id="S001">
        <name>张三</name>
        <age>18</age>
        <courses>
            <course>数学</course>
            <course>物理</course>
            <course>化学</course>
        </courses>
    </student>
    <student id="S002">
        <name>李四</name>
        <age>19</age>
        <courses>
            <course>语文</course>
            <course>英语</course>
        </courses>
    </student>
</students>

对应的 Java 类如下:

Student.java

import java.util.List;
public class Student {
    private String id;
    private String name;
    private int age;
    private List<String> courses;
    // 必须提供一个无参构造函数,XStream 需要它
    public Student() {
    }
    // 为了方便查看结果,添加一个有参构造函数和 toString() 方法
    public Student(String id, String name, int age, List<String> courses) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.courses = courses;
    }
    // Getters and Setters (非常重要)
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public List<String> getCourses() { return courses; }
    public void setCourses(List<String> courses) { this.courses = courses; }
    @Override
    public String toString() {
        return "Student{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", courses=" + courses +
                '}';
    }
}

Students.java (用于包装多个 Student 对象)

dom4j如何将XML转为Java对象?-图3
(图片来源网络,侵删)
import java.util.List;
public class Students {
    private List<Student> student;
    // Getters and Setters
    public List<Student> getStudent() {
        return student;
    }
    public void setStudent(List<Student> student) {
        this.student = student;
    }
}

第 3 步:编写转换代码

我们可以编写主程序来读取 XML 并将其转换为 Students 对象。

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.util.List;
public class XmlToObjectConverter {
    public static void main(String[] args) {
        // 1. 定义 XML 文件路径
        File xmlFile = new File("src/main/resources/student.xml");
        // 2. 创建 XStream 实例
        // DomDriver 是 XStream 默认的驱动,它内部使用 DOM 解析器,我们可以直接使用 dom4j 的 SAXReader
        XStream xstream = new XStream(new DomDriver());
        // 3. 设置 XML 标签与 Java 类的别名
        // 这一步很重要,它告诉 XStream <students> 标签对应 Students 类
        xstream.alias("students", Students.class);
        xstream.alias("student", Student.class);
        // 如果想为 <course> 标签设置别名,也可以加上
        // xstream.alias("course", String.class); // 对于简单类型,通常可以省略
        // 4. (可选) 处理集合标签的别名
        // 默认情况下,XStream 会将 List<Student> 映射为 <list> 标签。
        // 如果你的 XML 中使用的是 <student> 作为集合项,可以设置以下属性来避免生成 <list> 标签。
        xstream.addImplicitCollection(Students.class, "student", "student", Student.class);
        // 解释:
        // - Students.class: 在哪个类中查找这个集合
        // - "student": 这个集合在 Students 类中的属性名 (getStudent())
        // - "student": XML 中集合项的标签名
        // - Student.class: 集合中元素的类型
        // 5. (可选) 处理属性
        // 如果想将 <student id="S001"> 中的 id 属性映射到 Student 类的 id 字段
        xstream.useAttributeFor(Student.class, "id");
        xstream.aliasField("id", Student.class, "id");
        try {
            // 6. 使用 dom4j 的 SAXReader 读取 XML 文件,得到 Document 对象
            SAXReader reader = new SAXReader();
            Document document = reader.read(xmlFile);
            // 7. 将 Document 对象转换为字符串
            // XStream 可以直接解析字符串形式的 XML
            String xmlString = document.asXML();
            // 8. 使用 XStream 将 XML 字符串转换为 Java 对象
            Students students = (Students) xstream.fromXML(xmlString);
            // 9. 验证结果
            System.out.println("转换成功!获取到的学生列表:");
            List<Student> studentList = students.getStudent();
            for (Student student : studentList) {
                System.out.println(student);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }
}

代码解释

  1. XStream xstream = new XStream(new DomDriver());: 创建 XStream 实例,并指定使用 DOM 驱动来解析 XML。
  2. xstream.alias("students", Students.class);: 设置别名,这告诉 XStream,在解析 XML 时,遇到 <students> 标签,就创建一个 Students 类的实例,这可以让你在 XML 中使用更语义化的标签名(如 <students>),而 Java 类名可以是 Students
  3. xstream.addImplicitCollection(...): 这是一个非常实用的技巧,当你的 XML 结构是 <students><student>...</student><student>...</student></students> 时,XStream 默认会生成 <students><list><student>...</student></list></students>,通过这个设置,我们告诉 XStream Students 类中的 student 列表是隐式的,其 XML 项的标签就是 student,从而保持了原始 XML 的结构。
  4. xstream.useAttributeFor(...): 将 XML 元素的属性映射为 Java 对象的字段。<student id="S001"> 中的 id 属性值会直接设置到 Student 对象的 id 字段上。
  5. SAXReader: 这是 dom4j 的核心类,用于将 XML 文件解析成 Document 对象。
  6. document.asXML(): 将 Document 对象转换回 XML 字符串,虽然这里有点“绕”,但它清晰地展示了 dom4j 和 XStream 的分工:dom4j 负责读取和解析文件,XStream 负责格式转换
  7. xstream.fromXML(xmlString): XStream 的核心方法,将 XML 字符串反序列化成 Java 对象。

纯 dom4j 手动转换 (不推荐,但有助于理解)

如果你不想引入 XStream,也可以完全使用 dom4j 手动进行转换,这种方式代码量更大,且 XML 结构稍有变化就需要修改代码,但能让你更深刻地理解 XML 解析的过程。

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class Dom4jManualConverter {
    public static void main(String[] args) {
        File xmlFile = new File("src/main/resources/student.xml");
        SAXReader reader = new SAXReader();
        List<Student> studentList = new ArrayList<>();
        try {
            Document document = reader.read(xmlFile);
            // 获取根元素 <students>
            Element rootElement = document.getRootElement();
            // 获取所有的 <student> 元素
            List<Element> studentElements = rootElement.elements("student");
            for (Element studentElement : studentElements) {
                // 创建 Student 对象
                Student student = new Student();
                // 1. 处理属性
                student.setId(studentElement.attributeValue("id"));
                // 2. 处理子元素
                Element nameElement = studentElement.element("name");
                if (nameElement != null) {
                    student.setName(nameElement.getText());
                }
                Element ageElement = studentElement.element("age");
                if (ageElement != null) {
                    student.setAge(Integer.parseInt(ageElement.getText()));
                }
                // 3. 处理列表 <courses>
                Element coursesElement = studentElement.element("courses");
                if (coursesElement != null) {
                    List<String> courses = new ArrayList<>();
                    for (Element courseElement : coursesElement.elements("course")) {
                        courses.add(courseElement.getText());
                    }
                    student.setCourses(courses);
                }
                studentList.add(student);
            }
            // 验证结果
            System.out.println("手动转换成功!获取到的学生列表:");
            for (Student student : studentList) {
                System.out.println(student);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }
}

手动转换的优缺点

  • 优点:
    • 不需要额外的依赖(除了 dom4j)。
    • 对转换过程有完全的控制权。
  • 缺点:
    • 代码冗长: 需要为每个字段编写获取和设置代码。
    • 脆弱性: XML 结构发生改变(<name> 标签改成了 <fullName>),代码就需要相应修改,维护成本高。
    • 重复性高: 如果有多个相似的 XML 结构,会产生大量重复代码。
特性 方案一 (dom4j + XStream) 方案二 (纯 dom4j 手动转换)
易用性 非常高,几行代码即可完成 ,需要大量样板代码
维护性 ,通过别名和注解适应结构变化 ,XML 结构变化需修改大量代码
灵活性 ,支持复杂映射、转换器等 ,只能处理标准映射
依赖 需要额外引入 XStream 库 只需 dom4j
适用场景 绝大多数项目,特别是需要处理复杂或频繁变化的 XML 时 简单、一次性、或对依赖有严格限制的小任务

在实际开发中,强烈推荐使用方案一(dom4j + XStream),它将“文件解析”和“对象转换”的职责清晰分离,代码简洁、健壮且易于维护,是处理 XML 与 Java 对象转换的行业标准做法之一。

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