在Android应用开发中,经常会遇到需要解析XML格式数据的场景,比如解析服务端的配置信息、接口返回的XML格式数据等。DOM和基于SAXParserFactory的SAX解析是两种常用的XML解析方案,两者的实现逻辑和适用场景有明显差异,掌握它们的使用方法能更高效地完成XML解析工作。

DOM解析XML的使用方法
DOM解析的核心思路是先将整个XML文档加载到内存中,构建出一棵节点树,然后通过遍历节点树获取需要的数据。这种方式可以随机访问任意节点,操作灵活,但内存占用相对较高,不适合解析过大的XML文件。
DOM解析的实现步骤
- 获取XML文件的输入流,可以是本地assets目录下的文件,也可以是网络请求返回的输入流
- 创建
DocumentBuilderFactory实例,再通过它获取DocumentBuilder实例 - 调用
DocumentBuilder的parse方法解析输入流,得到Document对象 - 通过
Document对象获取根节点,再逐层遍历子节点获取数据
DOM解析代码示例
以下示例解析assets目录下的student.xml文件,文件内容如下:
<?xml version="1.0" encoding="utf-8"?>
<students>
<student id="1">
<name>张三</name>
<age>20</age>
<major>计算机科学</major>
</student>
<student id="2">
<name>李四</name>
<age>21</age>
<major>软件工程</major>
</student>
</students>对应的解析代码:
import android.content.res.AssetManager;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;
public class DomXmlParser {
public void parseXml(AssetManager assetManager) {
try {
// 获取XML文件输入流
InputStream is = assetManager.open("student.xml");
// 创建DocumentBuilderFactory实例
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 获取DocumentBuilder实例
DocumentBuilder builder = factory.newDocumentBuilder();
// 解析输入流得到Document对象
Document document = builder.parse(is);
// 获取根节点students
Element rootElement = document.getDocumentElement();
// 获取所有student节点
NodeList studentNodes = rootElement.getElementsByTagName("student");
for (int i = 0; i < studentNodes.getLength(); i++) {
Node studentNode = studentNodes.item(i);
if (studentNode.getNodeType() == Node.ELEMENT_NODE) {
Element studentElement = (Element) studentNode;
// 获取student节点的id属性
String id = studentElement.getAttribute("id");
// 获取name子节点内容
String name = studentElement.getElementsByTagName("name").item(0).getTextContent();
// 获取age子节点内容
String age = studentElement.getElementsByTagName("age").item(0).getTextContent();
// 获取major子节点内容
String major = studentElement.getElementsByTagName("major").item(0).getTextContent();
// 打印解析结果
System.out.println("学生ID:" + id + ",姓名:" + name + ",年龄:" + age + ",专业:" + major);
}
}
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}使用SAXParserFactory实现SAX解析
SAX解析是基于事件驱动的模式,解析时会逐行读取XML内容,遇到不同的节点(如开始标签、结束标签、文本内容)时触发对应的回调方法,不需要将整个文档加载到内存,内存占用低,适合解析大体积XML文件,但无法随机访问节点,只能顺序解析。
SAX解析的实现步骤
- 创建
SAXParserFactory实例,通过它获取SAXParser实例 - 自定义
DefaultHandler的子类,重写事件回调方法,在回调中处理解析到的数据 - 调用
SAXParser的parse方法,传入XML输入流和自定义的Handler实例
SAXParserFactory解析代码示例
同样解析上面的student.xml文件,自定义Handler类:
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.ArrayList;
import java.util.List;
public class StudentHandler extends DefaultHandler {
private List<Student> studentList;
private Student currentStudent;
private String currentTagName;
public List<Student> getStudentList() {
return studentList;
}
@Override
public void startDocument() throws SAXException {
super.startDocument();
studentList = new ArrayList<>();
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
currentTagName = qName;
if ("student".equals(qName)) {
currentStudent = new Student();
// 获取id属性
String id = attributes.getValue("id");
currentStudent.setId(id);
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
if (currentStudent != null && currentTagName != null) {
String content = new String(ch, start, length).trim();
if ("name".equals(currentTagName)) {
currentStudent.setName(content);
} else if ("age".equals(currentTagName)) {
currentStudent.setAge(content);
} else if ("major".equals(currentTagName)) {
currentStudent.setMajor(content);
}
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
if ("student".equals(qName)) {
studentList.add(currentStudent);
currentStudent = null;
}
currentTagName = null;
}
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
}
// 学生实体类
class Student {
private String id;
private String name;
private String age;
private String major;
// 省略getter和setter方法
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 String getAge() { return age; }
public void setAge(String age) { this.age = age; }
public String getMajor() { return major; }
public void setMajor(String major) { this.major = major; }
}调用解析的代码:
import android.content.res.AssetManager;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.InputStream;
public class SaxXmlParser {
public void parseXml(AssetManager assetManager) {
try {
// 获取XML文件输入流
InputStream is = assetManager.open("student.xml");
// 创建SAXParserFactory实例
SAXParserFactory factory = SAXParserFactory.newInstance();
// 获取SAXParser实例
SAXParser parser = factory.newSAXParser();
// 创建自定义Handler
StudentHandler handler = new StudentHandler();
// 开始解析
parser.parse(is, handler);
// 获取解析结果
for (Student student : handler.getStudentList()) {
System.out.println("学生ID:" + student.getId() + ",姓名:" + student.getName() + ",年龄:" + student.getAge() + ",专业:" + student.getMajor());
}
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}两种解析方式的对比与选择
开发者可以根据实际场景选择合适的解析方式:
| 对比项 | DOM解析 | SAX解析(SAXParserFactory) |
|---|---|---|
| 内存占用 | 较高,需要加载整个文档到内存 | 较低,逐行读取,不需要全量加载 |
| 访问方式 | 支持随机访问任意节点 | 只能顺序访问,无法回退 |
| 适用场景 | XML文档较小,需要频繁操作节点数据 | XML文档较大,只需要顺序读取数据 |
| 实现复杂度 | 逻辑简单,代码直观 | 需要自定义Handler,逻辑稍复杂 |
注意事项
- 解析网络XML时需要在子线程中执行,避免阻塞主线程,同时需要申请网络权限
- 解析完成后及时关闭输入流,避免资源泄漏
- 如果遇到XML格式不规范的情况,两种解析方式都可能抛出异常,需要做好异常处理
- 如果XML文件过大,优先选择SAX解析,避免内存溢出
DOM解析SAXParserFactoryXML解析Android修改时间:2026-06-06 14:32:29