导读:本期聚焦于小伙伴创作的《Java中如何解析XML?DOM、SAX、StAX与Dom4j四种方式详解》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Java中如何解析XML?DOM、SAX、StAX与Dom4j四种方式详解》有用,将其分享出去将是对创作者最好的鼓励。

Java中对XML的解析详解

XML(可扩展标记语言)是一种常用于存储和传输结构化数据的格式,在配置文件、数据交换等场景中应用广泛。Java生态中提供了多种XML解析方式,不同方式各有适用场景,本文将对常见的解析方案进行详细说明。

常见XML解析方式分类

Java中的XML解析方式主要分为两类:

  • DOM解析:将整个XML文档加载到内存中,形成树形结构,允许随机访问和修改文档内容
  • SAX解析:基于事件驱动的流式解析,逐行读取XML内容,不需要加载整个文档到内存,适合处理大体积XML
  • StAX解析:同样基于流的方式,但由应用程序主动控制解析进度,相比SAX更灵活
  • 第三方库解析:如JDOM、Dom4j等,对原生解析方式进行了封装,使用更便捷

DOM解析实战

DOM(Document Object Model)解析是Java原生支持的解析方式,核心思路是把XML文档转换为内存中的节点树,每个节点对应XML的元素、属性、文本等内容。这种方式的优点是支持对文档的增删改查,缺点是处理大文件时内存占用较高。

以下是一个简单的DOM解析示例,假设我们要解析的XML文件内容为:

<?xml version="1.0" encoding="UTF-8"?>
<users>
    <user id="1">
        <name>张三</name>
        <age>25</age>
        <email>zhangsan@ipipp.com</email>
    </user>
    <user id="2">
        <name>李四</name>
        <age>28</age>
        <email>lisi@ipipp.com</email>
    </user>
</users>

对应的DOM解析代码如下:

import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.File;

public class DomParseDemo {
    public static void main(String[] args) {
        try {
            // 1. 创建DOM解析器工厂
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            // 2. 创建DOM解析器
            DocumentBuilder builder = factory.newDocumentBuilder();
            // 3. 解析XML文件,得到Document对象(整个文档的树形结构)
            Document document = builder.parse(new File("users.xml"));

            // 4. 获取根节点 users
            Element root = document.getDocumentElement();
            System.out.println("根节点名称:" + root.getNodeName());

            // 5. 获取所有user节点
            NodeList userList = root.getElementsByTagName("user");
            System.out.println("用户总数:" + userList.getLength());

            // 6. 遍历每个user节点
            for (int i = 0; i < userList.getLength(); i++) {
                Node userNode = userList.item(i);
                if (userNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element userElement = (Element) userNode;
                    // 获取user节点的id属性
                    String id = userElement.getAttribute("id");
                    System.out.println("\n用户ID:" + id);

                    // 获取name子节点内容
                    String name = userElement.getElementsByTagName("name").item(0).getTextContent();
                    // 获取age子节点内容
                    String age = userElement.getElementsByTagName("age").item(0).getTextContent();
                    // 获取email子节点内容
                    String email = userElement.getElementsByTagName("email").item(0).getTextContent();

                    System.out.println("姓名:" + name);
                    System.out.println("年龄:" + age);
                    System.out.println("邮箱:" + email);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

上述代码首先通过DocumentBuilderFactoryDocumentBuilder创建解析器,再将XML文件解析为Document对象,之后通过节点操作方法获取需要的内容。如果需要修改XML内容,比如新增用户、修改年龄等,也可以直接操作Document对象,最后通过Transformer将修改后的内容写回文件。

SAX解析实战

SAX(Simple API for XML)是基于事件驱动的解析方式,解析器在读取XML的过程中,遇到开始标签、结束标签、文本内容等会触发对应的事件,应用程序通过实现事件处理器来响应这些事件,从而获取XML中的数据。这种方式不需要加载整个文档到内存,适合处理大体积XML,但不支持修改文档内容,也不支持随机访问。

以下是一个SAX解析的示例,解析上述同样的users.xml文件:

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.*;
import java.io.File;

public class SaxParseDemo {
    public static void main(String[] args) {
        try {
            // 1. 创建SAX解析器工厂
            SAXParserFactory factory = SAXParserFactory.newInstance();
            // 2. 创建SAX解析器
            SAXParser parser = factory.newSAXParser();
            // 3. 创建事件处理器
            DefaultHandler handler = new DefaultHandler() {
                // 当前解析的用户ID
                private String currentId;
                // 当前解析的节点名称
                private String currentTag;
                // 用户姓名
                private String name;
                // 用户年龄
                private String age;
                // 用户邮箱
                private String email;

                // 遇到开始标签时触发
                @Override
                public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
                    currentTag = qName;
                    if ("user".equals(qName)) {
                        // 获取user节点的id属性
                        currentId = attributes.getValue("id");
                        System.out.println("\n开始解析用户,ID:" + currentId);
                    }
                }

                // 遇到文本内容时触发
                @Override
                public void characters(char[] ch, int start, int length) throws SAXException {
                    String content = new String(ch, start, length).trim();
                    if (!content.isEmpty()) {
                        if ("name".equals(currentTag)) {
                            name = content;
                        } else if ("age".equals(currentTag)) {
                            age = content;
                        } else if ("email".equals(currentTag)) {
                            email = content;
                        }
                    }
                }

                // 遇到结束标签时触发
                @Override
                public void endElement(String uri, String localName, String qName) throws SAXException {
                    if ("user".equals(qName)) {
                        // 一个user节点解析完成,输出内容
                        System.out.println("姓名:" + name);
                        System.out.println("年龄:" + age);
                        System.out.println("邮箱:" + email);
                        // 重置临时变量
                        name = null;
                        age = null;
                        email = null;
                        currentId = null;
                    }
                    currentTag = null;
                }
            };
            // 4. 开始解析
            parser.parse(new File("users.xml"), handler);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

上述代码通过继承DefaultHandler类实现自己的事件处理器,重写startElementcharactersendElement等方法,在解析过程中收集需要的数据。SAX解析的过程中,程序只能按顺序处理XML内容,无法回溯已经解析过的内容。

StAX解析实战

StAX(Streaming API for XML)是Java 6之后引入的解析方式,同样基于流,但不同于SAX的被动事件驱动,StAX由应用程序主动调用方法从解析器中获取下一个事件,控制更灵活。StAX分为游标API和迭代器API两种使用方式,以下示例使用更常用的游标API。

import javax.xml.stream.*;
import javax.xml.stream.events.XMLEvent;
import java.io.FileInputStream;

public class StaxParseDemo {
    public static void main(String[] args) {
        try {
            // 1. 创建XML输入工厂
            XMLInputFactory factory = XMLInputFactory.newInstance();
            // 2. 创建XML事件阅读器
            XMLEventReader reader = factory.createXMLEventReader(new FileInputStream("users.xml"));

            // 临时变量
            String currentId = null;
            String name = null;
            String age = null;
            String email = null;

            // 3. 循环获取下一个事件,直到文档结束
            while (reader.hasNext()) {
                XMLEvent event = reader.nextEvent();
                // 处理开始元素事件
                if (event.isStartElement()) {
                    String tagName = event.asStartElement().getName().getLocalPart();
                    if ("user".equals(tagName)) {
                        // 获取user节点的id属性
                        currentId = event.asStartElement().getAttributeByName(new javax.xml.namespace.QName("id")).getValue();
                        System.out.println("\n开始解析用户,ID:" + currentId);
                    } else if ("name".equals(tagName)) {
                        // 获取name标签的文本内容
                        name = reader.nextEvent().asCharacters().getData();
                    } else if ("age".equals(tagName)) {
                        age = reader.nextEvent().asCharacters().getData();
                    } else if ("email".equals(tagName)) {
                        email = reader.nextEvent().asCharacters().getData();
                    }
                }
                // 处理结束元素事件
                if (event.isEndElement()) {
                    if ("user".equals(event.asEndElement().getName().getLocalPart())) {
                        // 一个user节点解析完成,输出内容
                        System.out.println("姓名:" + name);
                        System.out.println("年龄:" + age);
                        System.out.println("邮箱:" + email);
                        // 重置临时变量
                        name = null;
                        age = null;
                        email = null;
                        currentId = null;
                    }
                }
            }
            // 关闭资源
            reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

StAX的游标API使用起来比较直观,开发者可以灵活控制解析的进度,比如遇到某个条件时可以提前停止解析,不需要像SAX那样必须处理完整个文档。

第三方库Dom4j解析

Dom4j是一个开源的XML解析库,对DOM和SAX进行了封装,提供了更简洁的API,使用非常广泛。使用前需要导入Dom4j的依赖,如果是Maven项目,可以在pom.xml中添加以下依赖:

<dependency>
    <groupId>org.dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>2.1.3</version>
</dependency>

以下是使用Dom4j解析users.xml的示例:

import org.dom4j.*;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.util.List;

public class Dom4jParseDemo {
    public static void main(String[] args) {
        try {
            // 1. 创建SAXReader对象
            SAXReader reader = new SAXReader();
            // 2. 读取XML文件,得到Document对象
            Document document = reader.read(new File("users.xml"));
            // 3. 获取根节点
            Element root = document.getRootElement();
            System.out.println("根节点名称:" + root.getName());

            // 4. 获取所有user子节点
            List<Element> userElements = root.elements("user");
            System.out.println("用户总数:" + userElements.size());

            // 5. 遍历user节点
            for (Element userElement : userElements) {
                // 获取id属性
                String id = userElement.attributeValue("id");
                System.out.println("\n用户ID:" + id);
                // 获取name子节点内容
                String name = userElement.elementText("name");
                // 获取age子节点内容
                String age = userElement.elementText("age");
                // 获取email子节点内容
                String email = userElement.elementText("email");

                System.out.println("姓名:" + name);
                System.out.println("年龄:" + age);
                System.out.println("邮箱:" + email);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Dom4j的API非常简洁,比如获取子节点内容直接使用elementText方法,不需要像原生DOM那样先获取节点列表再取内容,大大降低了编码复杂度,同时它也支持对XML文档的修改和创建。如果需要创建新的XML文档,Dom4j也提供了非常便捷的API,比如通过DocumentHelper.createElement创建节点,再组装成完整的文档结构。

不同解析方式的选型建议

解析方式优点缺点适用场景
DOM解析支持随机访问、增删改查,API直观内存占用高,不适合大文件小体积XML,需要修改文档内容的场景
SAX解析内存占用低,解析速度快不支持随机访问和内容修改,编码相对复杂大体积XML,只需要读取内容不需要修改的场景
StAX解析内存占用低,应用程序可控制解析进度API相对DOM复杂一些大体积XML,需要灵活控制解析过程的场景
Dom4jAPI简洁易用,功能全面需要引入第三方依赖绝大多数XML解析场景,尤其是需要快速开发的情况

在实际开发中,如果没有特殊的内存限制,优先选择Dom4j等第三方库可以大幅提升开发效率;如果是Android开发等对环境依赖要求严格的场景,可以考虑使用原生的DOM或StAX解析。

Java_XML解析DOM解析SAX解析StAX解析Dom4j 本作品最后修改时间:2026-05-22 21:45:03

免责声明:网站部分内容来源于网络或由用户自行发表,内容观点不代表本站立场。本站是个人网站免费分享,内容仅供个人学习、研究或参考使用,如内容中引用了第三方作品,其版权归原作者所有。若内容触犯了您的权益,请联系我们进行处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。前端、网络、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握网站开发与运维所需的核心技术栈。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端逻辑,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。