当前位置: 首页 > news >正文

4种XML解析方式详解

详细讲解四种主流的XML解析方式,包括其原理、特点、适用场景和代码示例。

四种方式,可以分为两大类:

  1. 基于树的解析:将整个XML文档一次性加载到内存,形成一棵树形结构。
    • DOM
  2. 基于事件的解析:顺序读取XML文档,遇到节点时触发事件,边读边解析。
    • SAX
    • StAX
  3. 绑定类解析:通过映射关系,将XML节点直接绑定到程序中的对象。
    • JAXB

1. DOM - 文档对象模型 bG9pajNqLmNvbQ== loij3j.combG9pajNqLmNvbQ==

核心思想

一次性将整个XML文档读入内存,构建一个树形结构(Document对象)。程序可以通过操作这棵树上的节点(Node、Element、Attribute等)来随机访问和修改XML的任何部分。

工作流程

  1. 创建解析器工厂。
  2. 由工厂创建解析器。
  3. 解析器解析XML源(文件、输入流等),生成一个Document对象。
  4. 程序从Document对象开始,使用getElementsByTagNamegetChildNodes等方法遍历和操作节点。

代码示例 (Java) bG9pajNqLmNvbQ== loij3j.combG9pajNqLmNvbQ==

假设有 books.xml 文件:

<?xml version="1.0" encoding="UTF-8"?>
<bookstore><book id="1"><title>Java Programming</title><author>James Gosling</author><price>49.99</price></book><book id="2"><title>XML Guide</title><author>John Doe</author><price>39.95</price></book>
</bookstore>

使用DOM解析的Java代码:

import org.w3c.dom.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;public class DomParserExample {public static void main(String[] args) {try {// 1. 创建DocumentBuilderFactoryDocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();// 2. 创建DocumentBuilderDocumentBuilder builder = factory.newDocumentBuilder();// 3. 解析XML文件,获取Document对象Document document = builder.parse(new File("books.xml"));// 可选:规范化文档(合并相邻文本节点等)document.getDocumentElement().normalize();// 4. 获取所有book节点NodeList nodeList = document.getElementsByTagName("book");// 5. 遍历节点列表for (int i = 0; i < nodeList.getLength(); i++) {Node node = nodeList.item(i);if (node.getNodeType() == Node.ELEMENT_NODE) {Element element = (Element) node;// 获取属性String id = element.getAttribute("id");System.out.println("Book ID: " + id);// 获取子元素内容String title = element.getElementsByTagName("title").item(0).getTextContent();String author = element.getElementsByTagName("author").item(0).getTextContent();String price = element.getElementsByTagName("price").item(0).getTextContent();System.out.printf("Title: %s, Author: %s, Price: %s\n", title, author, price);System.out.println("---------------");}}} catch (Exception e) {e.printStackTrace();}}
}

优缺点 bG9pajNqLmNvbQ== loij3j.combG9pajNqLmNvbQ==

  • 优点
    • 随机访问:可以方便地访问和修改任意节点。
    • 支持修改:可以轻松地对文档结构进行增删改查。
    • 易于编程:API直观,符合面向对象思想。
  • 缺点
    • 内存消耗大:整个文档必须加载到内存中,不适合处理大型XML文件(如几个GB)。
    • 性能相对较低:解析和构建整个树结构需要时间。

适用场景 bG9pajNqLmNvbQ== loij3j.combG9pajNqLmNvbQ==

  • 需要随机访问XML文档的任意部分。
  • XML文档大小可控(通常小于几十MB)。
  • 需要对XML结构进行修改。

2. SAX - 简单API for XML

核心思想

基于事件驱动的推模型。解析器顺序读取XML文档,当遇到文档开始、元素开始、元素结束、文本内容等事件时,会调用程序中预先注册的回调方法。程序不持有整个文档的结构,只能被动地接收事件。

工作流程 bG9pajNqLmNvbQ== loij3j.combG9pajNqLmNvbQ==

  1. 创建SAXParserFactory和SAXParser。
  2. 创建一个继承自DefaultHandler的处理器。
  3. 重写处理器中的关键方法(如startElement, endElement, characters)。
  4. 解析器开始解析,在解析过程中自动调用处理器的相关方法。

代码示例 (Java) bG9pajNqLmNvbQ== loij3j.combG9pajNqLmNvbQ==

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.File;public class SaxParserExample {public static void main(String[] args) {try {// 1. 创建SAXParserFactory和SAXParserSAXParserFactory factory = SAXParserFactory.newInstance();SAXParser saxParser = factory.newSAXParser();// 2. 创建自定义的处理器BookHandler handler = new BookHandler();// 3. 开始解析saxParser.parse(new File("books.xml"), handler);} catch (Exception e) {e.printStackTrace();}}
}// 自定义事件处理器
class BookHandler extends DefaultHandler {private String currentValue;private String currentId;private boolean inBook = false;// 遇到元素开始时调用@Overridepublic void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {currentValue = ""; // 清空当前值if ("book".equals(qName)) {inBook = true;// 获取属性currentId = attributes.getValue("id");System.out.println("Book ID: " + currentId);}}// 遇到元素结束时调用@Overridepublic void endElement(String uri, String localName, String qName) throws SAXException {if (inBook) {switch (qName) {case "title":System.out.println("Title: " + currentValue);break;case "author":System.out.println("Author: " + currentValue);break;case "price":System.out.println("Price: " + currentValue);break;case "book":System.out.println("---------------");inBook = false;break;}}}// 处理元素内的文本内容@Overridepublic void characters(char[] ch, int start, int length) throws SAXException {// 累积文本内容(这个方法可能会被多次调用)currentValue += new String(ch, start, length).trim();}
}

优缺点 bG9pajNqLmNvbQ== loij3j.combG9pajNqLmNvbQ==

  • 优点
    • 内存效率高:不需要将整个文档加载到内存,适合处理大型XML文件。
    • 速度快:因为是流式解析,延迟低。
  • 缺点
    • 只读:无法修改XML文档。
    • 编程复杂:需要维护解析状态,逻辑相对复杂。
    • 随机访问能力差:无法直接跳转到某个特定节点。

适用场景 bG9pajNqLmNvbQ== loij3j.combG9pajNqLmNvbQ==

  • 只需要读取XML数据,不需要修改。
  • 处理非常大的XML文件。
  • 只需要XML中的部分数据,可以在找到所需数据后停止解析。

3. StAX - 用于XML的流API bG9pajNqLmNvbQ== loij3j.combG9pajNqLmNvbQ==

核心思想

基于迭代器的拉模型。程序可以主动地从解析器中“拉取”事件(如开始元素、结束元素),控制权在程序手中。它结合了SAX的高效和DOM的易用性。

工作流程 bG9pajNqLmNvbQ== loij3j.combG9pajNqLmNvbQ==

  1. 创建XMLInputFactory。
  2. 创建XMLEventReader(或XMLStreamReader)。
  3. 使用hasNext()nextEvent()循环遍历解析事件。
  4. 根据事件的类型(START_ELEMENT, CHARACTERS, END_ELEMENT)进行相应处理。

代码示例 (Java) bG9pajNqLmNvbQ== loij3j.combG9pajNqLmNvbQ==

import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.events.*;
import java.io.FileReader;public class StaxParserExample {public static void main(String[] args) {try {// 1. 创建XMLInputFactoryXMLInputFactory factory = XMLInputFactory.newInstance();// 2. 创建XMLEventReaderXMLEventReader eventReader = factory.createXMLEventReader(new FileReader("books.xml"));String currentId = null;String currentTag = null;// 3. 迭代处理事件while (eventReader.hasNext()) {XMLEvent event = eventReader.nextEvent();switch (event.getEventType()) {case XMLStreamConstants.START_ELEMENT:StartElement startElement = event.asStartElement();String qName = startElement.getName().getLocalPart();if ("book".equals(qName)) {// 获取属性Attribute idAttr = startElement.getAttributeByName(new javax.xml.namespace.QName("id"));if (idAttr != null) {currentId = idAttr.getValue();System.out.println("Book ID: " + currentId);}}currentTag = qName; // 记录当前标签名break;case XMLStreamConstants.CHARACTERS:Characters characters = event.asCharacters();String data = characters.getData().trim();if (data.length() > 0 && currentTag != null) {switch (currentTag) {case "title":System.out.println("Title: " + data);break;case "author":System.out.println("Author: " + data);break;case "price":System.out.println("Price: " + data);break;}}break;case XMLStreamConstants.END_ELEMENT:EndElement endElement = event.asEndElement();if ("book".equals(endElement.getName().getLocalPart())) {System.out.println("---------------");currentTag = null;}break;}}} catch (Exception e) {e.printStackTrace();}}
}

优缺点

  • 优点
    • 内存效率高:与SAX一样是流式处理。
    • 控制灵活:拉模型让程序可以控制解析流程,更容易处理复杂逻辑。
    • 易于使用:相比SAX,API更直观,不需要复杂的回调。
  • 缺点
    • 只读:标准StAX API是只读的(虽然有扩展可以支持写入)。

适用场景 bG9pajNqLmNvbQ== loij3j.combG9pajNqLmNvbQ==

  • 需要流式解析的高性能和高效率。
  • 希望比SAX更直观地控制解析过程。
  • 需要过滤XML文档,只处理感兴趣的部分。

4. JAXB - Java架构绑定 bG9pajNqLmNvbQ== loij3j.combG9pajNqLmNvbQ==

核心思想

通过注解将Java类与XML模式绑定。它可以将XML数据反序列化(Unmarshalling) 为Java对象,也可以将Java对象序列化(Marshalling) 为XML数据。这是一种最高级、最便捷的解析方式。

工作流程 bG9pajNqLmNvbQ== loij3j.combG9pajNqLmNvbQ==

  1. 创建带有JAXB注解的Java类(或通过XSD生成)。
  2. 创建JAXBContext。
  3. 使用Unmarshaller将XML转换为Java对象。
  4. 使用Marshaller将Java对象转换为XML。

代码示例 (Java) bG9pajNqLmNvbQ== loij3j.combG9pajNqLmNvbQ==

1. 创建带注解的Java类:

import javax.xml.bind.annotation.*;@XmlRootElement(name = "bookstore")
@XmlAccessorType(XmlAccessType.FIELD)
public class Bookstore {@XmlElement(name = "book")private List<Book> books = new ArrayList<>();// Getter and Setterpublic List<Book> getBooks() { return books; }public void setBooks(List<Book> books) { this.books = books; }
}@XmlAccessorType(XmlAccessType.FIELD)
public class Book {@XmlAttributeprivate String id;@XmlElementprivate String title;@XmlElementprivate String author;@XmlElementprivate double price;// Getters and Setterspublic String getId() { return id; }public void setId(String id) { this.id = id; }public String getTitle() { return title; }public void setTitle(String title) { this.title = title; }public String getAuthor() { return author; }public void setAuthor(String author) { this.author = author; }public double getPrice() { return price; }public void setPrice(double price) { this.price = price; }
}

2. 使用JAXB解析XML:

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.File;public class JaxbParserExample {public static void main(String[] args) {try {// 1. 创建JAXBContext(指定包含的类)JAXBContext context = JAXBContext.newInstance(Bookstore.class);// 2. 创建UnmarshallerUnmarshaller unmarshaller = context.createUnmarshaller();// 3. 将XML反序列化为Java对象Bookstore bookstore = (Bookstore) unmarshaller.unmarshal(new File("books.xml"));// 4. 像操作普通Java对象一样操作数据for (Book book : bookstore.getBooks()) {System.out.println("Book ID: " + book.getId());System.out.println("Title: " + book.getTitle());System.out.println("Author: " + book.getAuthor());System.out.println("Price: " + book.getPrice());System.out.println("---------------");}} catch (JAXBException e) {e.printStackTrace();}}
}

优缺点

  • 优点
    • 开发效率极高:无需关心XML解析细节,直接操作对象。
    • 类型安全:在编译期就能发现类型错误。
    • 代码简洁:大大减少了样板代码。
  • 缺点
    • 内存消耗:与DOM类似,需要将整个对象树加载到内存。
    • 需要预定义类:需要提前创建与XML结构对应的Java类。
    • 灵活性稍差:对于不规则或动态结构的XML处理起来比较麻烦。

适用场景 bG9pajNqLmNvbQ== loij3j.combG9pajNqLmNvbQ==

  • XML文档有固定的、已知的模式(XSD)。
  • 追求开发效率和代码可维护性。
  • 需要在Java对象和XML之间频繁转换。

总结对比 bG9pajNqLmNvbQ== loij3j.combG9pajNqLmNvbQ==

特性 DOM SAX StAX JAXB
解析模型 树形模型 事件驱动(推) 事件驱动(拉) 对象绑定
内存占用
速度 中等
是否可写 是(扩展)
访问方式 随机访问 顺序只读 顺序只读 随机访问(对象)
编程复杂度 简单 复杂 中等 非常简单
适用场景 小文件、需修改 大文件、只读 大文件、需控制流程 已知模式、追求效率

选择建议: bG9pajNqLmNvbQ== loij3j.combG9pajNqLmNvbQ==

  • 小配置文件,且需修改:选 DOM
  • 读取超大XML日志文件:选 SAXStAX(推荐StAX)
  • 已知XML结构,追求开发速度:选 JAXB
  • 需要灵活控制解析过程:选 StAX
http://www.jsqmd.com/news/55556/

相关文章:

  • 20232415 2025-2026-1 《网络与系统攻防技术》实验七实验报告
  • 2025 Launch X431 PRO3 ACE: Online ECU Coding 38+ Services for Euro/Amer Vehicles with CANFD/DoIP
  • 2025-11-30 Expo Go(ios端)没有扫码的入口==》使用相机扫码,会自动弹出扫码入口,注意:开发环境和iphone连接的网络一定要是同一个!!
  • QtSingleapplication单实例-源码分析
  • 2025解决VS C# NUGET 安装System.Data.SQLite+SourceGear.SQLite3 不支持 AnyCPU 的系列问题
  • 102302156 李子贤 数据采集第四次作业
  • 东华萌新挑战赛 密室逃脱
  • 第40天(中等题 数据结构)
  • 核心功能详解
  • 2025-11-30-Nature Genetics | 本周最新文献速递
  • 效果-Element 3D
  • 2025苏州餐饮公司测评:苏州会议餐配送选这些,全区域超省心
  • 2025苏州承包食堂找哪家?苏州食堂承包优选清单
  • 2025不锈钢阀门厂家推荐:从口碑榜到销量榜清单在此
  • 2025脱酸脱盐设备公司有哪些:物料脱盐服务商优选指南
  • 2025隔音窗户哪个牌子好:广州隔音窗户哪家好盘点大测评
  • 截止阀厂家哪家好?2025截止阀品牌排行榜
  • 2025全自动吸吮式过滤器推荐厂家榜单
  • 旋片真空泵厂家有哪些2025真空系统厂家推荐
  • dotnet-dump安装、收集dump和崩溃自动收集dump
  • 虚拟机运行Vivado,部分界面显示不完全的问题
  • 《程序员修炼之道》笔记五
  • 商店礼包条目常用API
  • 《程序员修炼之道》笔记六
  • 账号诞生了,用做工作记录
  • 《程序员修炼之道》笔记四
  • wildshark
  • 后来,他长大了
  • 11月第三篇笔记
  • 11月29日总结 - 作业----