Xml作为结构化的数据格式,在配置文件、接口数据传输等场景中应用广泛,解析Xml是开发中常见的需求。目前主流的Xml解析方法分为四类,分别是基于树模型的DOM解析、基于事件流的SAX解析、基于拉模型的StAX解析以及第三方封装的JDOM解析,不同方法的实现逻辑和适用场景各有不同。

一、DOM解析方法
DOM即文档对象模型,解析时会将整个Xml文档加载到内存中,构建一个完整的树形结构,开发者可以通过操作树节点来获取Xml中的数据。这种方法的优点是便于修改Xml内容,缺点是大文件加载会占用较多内存。
以下是DOM解析Xml的示例代码,假设待解析的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解析的Java实现代码:
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
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 document = builder.parse(new File("users.xml"));
// 获取所有user节点
NodeList userNodes = document.getElementsByTagName("user");
for (int i = 0; i < userNodes.getLength(); i++) {
Element userElement = (Element) userNodes.item(i);
// 获取user节点的id属性
String userId = 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:" + userId + ",姓名:" + name + ",年龄:" + age);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
二、SAX解析方法
SAX即简单API for Xml,属于事件驱动的解析方式,解析时不会将整个文档加载到内存,而是按顺序读取Xml内容,遇到节点开始、节点结束、文本内容等事件时触发对应的回调方法。这种方法的优点是内存占用小,适合解析大文件,缺点是不能修改Xml内容,解析过程只能单向进行。
SAX解析需要实现DefaultHandler类来自定义事件处理逻辑,示例代码如下:
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 {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
// 自定义处理器
DefaultHandler handler = new DefaultHandler() {
// 当前解析的节点名称
private String currentNodeName = "";
// 用户ID临时存储
private String currentUserId = "";
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
currentNodeName = qName;
// 如果是user节点,获取id属性
if ("user".equals(qName)) {
currentUserId = attributes.getValue("id");
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
// 如果是name或age节点,输出内容
if ("name".equals(currentNodeName) || "age".equals(currentNodeName)) {
String content = new String(ch, start, length);
if ("name".equals(currentNodeName)) {
System.out.print("用户ID:" + currentUserId + ",姓名:" + content + ",");
} else {
System.out.println("年龄:" + content);
}
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
// 节点结束清空当前节点名称
currentNodeName = "";
}
};
parser.parse(new File("users.xml"), handler);
} catch (Exception e) {
e.printStackTrace();
}
}
}
三、StAX解析方法
StAX即流API for Xml,属于拉模型的解析方式,开发者可以主动控制解析进度,按需读取Xml中的事件,相比SAX的被动触发回调更加灵活。StAX同样不需要加载整个文档到内存,内存占用低,同时支持双向解析。
StAX解析的示例代码如下:
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
import java.io.FileInputStream;
public class StAXParseDemo {
public static void main(String[] args) {
try {
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = factory.createXMLStreamReader(new FileInputStream("users.xml"));
String currentUserId = "";
while (reader.hasNext()) {
int event = reader.next();
// 节点开始事件
if (event == XMLStreamReader.START_ELEMENT) {
String nodeName = reader.getLocalName();
if ("user".equals(nodeName)) {
currentUserId = reader.getAttributeValue(null, "id");
} else if ("name".equals(nodeName)) {
reader.next();
System.out.print("用户ID:" + currentUserId + ",姓名:" + reader.getText() + ",");
} else if ("age".equals(nodeName)) {
reader.next();
System.out.println("年龄:" + reader.getText());
}
}
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
四、JDOM解析方法
JDOM是第三方提供的Xml解析工具,它基于Java集合框架封装了Xml解析逻辑,使用起来比原生的DOM、SAX更加简洁,代码可读性更高。使用JDOM需要先在项目中导入对应的依赖包。
JDOM解析的示例代码如下:
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;
import java.io.File;
import java.util.List;
public class JDOMParseDemo {
public static void main(String[] args) {
try {
SAXBuilder builder = new SAXBuilder();
// 加载Xml文件生成Document对象
Document document = builder.build(new File("users.xml"));
// 获取根节点
Element rootElement = document.getRootElement();
// 获取所有user子节点
List<Element> userElements = rootElement.getChildren("user");
for (Element userElement : userElements) {
String userId = userElement.getAttributeValue("id");
String name = userElement.getChildText("name");
String age = userElement.getChildText("age");
System.out.println("用户ID:" + userId + ",姓名:" + name + ",年龄:" + age);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
四种解析方法对比
不同解析方法的特点和适用场景可以通过下表区分:
| 解析方法 | 内存占用 | 是否支持修改Xml | 适用场景 |
|---|---|---|---|
| DOM | 高 | 支持 | 小文件解析、需要修改Xml内容的场景 |
| SAX | 低 | 不支持 | 大文件解析、只需要读取数据的场景 |
| StAX | 低 | 不支持 | 大文件解析、需要灵活控制解析进度的场景 |
| JDOM | 高 | 支持 | 小文件解析、追求代码简洁性的场景 |
开发者可以根据实际的文件大小、功能需求选择合适的Xml解析方法,小文件且需要修改内容时优先选择DOM或JDOM,大文件只需要读取数据时优先选择SAX或StAX。