XML作为结构化的数据格式,在配置文件、数据交互等场景中被广泛使用,Java基础开发中提供了多种原生的XML解析方式,开发者可以根据实际需求选择合适的方案。不同的解析方式在内存占用、解析效率、使用复杂度上各有差异,掌握这些基础解析方法能应对大部分常规开发场景。

常见的Java XML解析方式
Java原生支持的XML解析方式主要分为三类,分别是DOM解析、SAX解析和StAX解析,三者的核心差异在于解析过程和适用场景不同。
DOM解析
DOM即文档对象模型,解析时会将整个XML文档加载到内存中,构建一个树形结构的文档对象,开发者可以通过操作这个树形对象来获取、修改XML中的数据。这种方式的优点是便于随机访问文档中的任意节点,操作直观,缺点是需要占用较多内存,不适合解析超大体积的XML文件。
DOM解析的基本使用步骤如下:
- 创建文档构建器工厂实例
- 通过工厂获取文档构建器
- 解析XML文件得到文档对象
- 通过文档对象获取根节点,再遍历子节点获取数据
以下是DOM解析XML的代码示例,假设待解析的XML文件名为user.xml,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<users>
<user id="1">
<name>张三</name>
<age>25</age>
</user>
<user id="2">
<name>李四</name>
<age>28</age>
</user>
</users>
对应的DOM解析代码:
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
public class DomParseDemo {
public static void main(String[] args) {
try {
// 创建文档构建器工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 获取文档构建器
DocumentBuilder builder = factory.newDocumentBuilder();
// 解析XML文件得到文档对象
Document document = builder.parse(new File("user.xml"));
// 获取根节点users
Element root = document.getDocumentElement();
// 获取所有user节点
NodeList userNodes = root.getElementsByTagName("user");
// 遍历user节点
for (int i = 0; i < userNodes.getLength(); i++) {
Element userElement = (Element) userNodes.item(i);
// 获取user节点的id属性
String id = userElement.getAttribute("id");
// 获取name子节点内容
String name = userElement.getElementsByTagName("name").item(0).getTextContent();
// 获取age子节点内容
String age = userElement.getElementsByTagName("age").item(0).getTextContent();
System.out.println("用户id:" + id + ",姓名:" + name + ",年龄:" + age);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
SAX解析
SAX即简单API for XML,是一种基于事件驱动的解析方式,解析时不会将整个文档加载到内存,而是逐行读取XML内容,遇到不同的节点(如开始标签、结束标签、文本内容)时触发对应的事件,开发者通过重写事件处理方法来实现数据获取。这种方式的优点是内存占用小,解析速度快,适合解析大体积XML文件,缺点是不能随机访问节点,只能顺序解析,且不支持修改XML内容。
SAX解析的基本使用步骤如下:
- 创建SAX解析器工厂实例
- 通过工厂获取SAX解析器
- 创建自定义的事件处理器,重写对应事件方法
- 解析XML文件并绑定事件处理器
以下是SAX解析上述user.xml的代码示例:
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 SaxParseDemo {
public static void main(String[] args) {
try {
// 创建SAX解析器工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
// 获取SAX解析器
SAXParser parser = factory.newSAXParser();
// 创建自定义事件处理器
DefaultHandler handler = new DefaultHandler() {
// 当前解析的user节点的id属性
private String currentId;
// 当前解析的标签名
private String currentTag;
// 开始解析元素时触发
@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");
}
}
// 解析到元素文本内容时触发
@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)) {
System.out.print("用户id:" + currentId + ",姓名:" + content + ",");
} else if ("age".equals(currentTag)) {
System.out.println("年龄:" + content);
}
}
}
// 结束解析元素时触发
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
currentTag = null;
}
};
// 解析XML文件
parser.parse(new File("user.xml"), handler);
} catch (Exception e) {
e.printStackTrace();
}
}
}
StAX解析
StAX即流式API for XML,是一种基于拉取模式的解析方式,开发者可以主动控制解析过程,通过循环拉取XML中的事件,再根据事件类型处理对应的数据。它结合了DOM和SAX的优点,内存占用小,同时支持开发者主动控制解析进度,使用起来比SAX更灵活。StAX主要分为两种编程模型,分别是迭代器模型和光标模型,实际开发中迭代器模型使用更普遍。
StAX迭代器模型解析的基本使用步骤如下:
- 创建XML输入工厂实例
- 通过工厂创建XML事件读取器
- 循环拉取事件,判断事件类型并处理
以下是StAX解析上述user.xml的代码示例:
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import java.io.FileInputStream;
import java.util.Iterator;
public class StaxParseDemo {
public static void main(String[] args) {
try {
// 创建XML输入工厂
XMLInputFactory factory = XMLInputFactory.newInstance();
// 创建XML事件读取器
XMLEventReader eventReader = factory.createXMLEventReader(new FileInputStream("user.xml"));
String currentId = null;
String currentTag = null;
// 循环拉取事件
while (eventReader.hasNext()) {
XMLEvent event = eventReader.nextEvent();
// 判断是开始元素事件
if (event.isStartElement()) {
StartElement startElement = event.asStartElement();
currentTag = startElement.getName().getLocalPart();
if ("user".equals(currentTag)) {
// 获取user节点的id属性
Iterator<Attribute> attributes = startElement.getAttributes();
while (attributes.hasNext()) {
Attribute attribute = attributes.next();
if ("id".equals(attribute.getName().getLocalPart())) {
currentId = attribute.getValue();
}
}
}
}
// 判断是字符事件(文本内容)
if (event.isCharacters()) {
String content = event.asCharacters().getData().trim();
if (!content.isEmpty()) {
if ("name".equals(currentTag)) {
System.out.print("用户id:" + currentId + ",姓名:" + content + ",");
} else if ("age".equals(currentTag)) {
System.out.println("年龄:" + content);
}
}
}
// 判断是结束元素事件
if (event.isEndElement()) {
currentTag = null;
}
}
eventReader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
三种解析方式的选择建议
在实际开发中,可以根据以下场景选择合适的解析方式:
| 解析方式 | 内存占用 | 随机访问 | 适用场景 |
|---|---|---|---|
| DOM解析 | 高 | 支持 | XML文件体积小,需要频繁修改、随机访问节点内容 |
| SAX解析 | 低 | 不支持 | XML文件体积大,只需要读取内容,不需要修改 |
| StAX解析 | 低 | 部分支持 | XML文件体积大,需要主动控制解析进度,灵活性要求高 |
如果开发中没有特殊需求,小体积XML文件优先选择DOM解析,开发效率更高,大体积文件优先选择StAX解析,兼顾性能和灵活性。