在Android应用开发中,XML是常用的数据存储和传输格式,SAX(Simple API for XML)作为轻量级的XML处理方案,采用事件驱动模式逐行读取XML内容,不需要一次性将整个文件加载到内存中,在处理大尺寸XML文件时相比DOM解析有明显的内存优势,同时Android也提供了对应的API支持用SAX创建XML文件,满足不同的业务需求。

SAX解析XML的核心原理
SAX解析的核心是事件驱动机制,解析器会从XML文件开头逐行扫描内容,当遇到不同的XML结构时触发对应的回调事件,开发者只需要实现对应的事件处理方法,就能获取到需要的XML数据。整个解析过程不需要构建完整的XML文档树,因此内存占用极低,适合移动端资源受限的场景。
SAX解析过程中会触发的主要事件包括:
- 文档开始:解析器开始处理XML文件时触发
- 元素开始:遇到<element>标签时触发
- 元素内容:读取到标签内的文本内容时触发
- 元素结束:遇到</element>标签时触发
- 文档结束:整个XML文件解析完成时触发
使用SAX创建XML文件
Android中创建XML文件可以使用SAXTransformerFactory配合TransformerHandler实现,这种方式同样遵循SAX的事件驱动逻辑,通过依次触发不同的节点创建事件,生成完整的XML结构。
以下是创建简单XML文件的完整示例代码,生成的XML包含一个根节点和多个子节点:
import android.util.Xml;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import java.io.File;
import java.io.FileOutputStream;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
public class SAXCreateXMLUtil {
public static void createXML(File outputFile) {
try {
// 获取SAXTransformerFactory实例
SAXTransformerFactory factory = (SAXTransformerFactory) TransformerFactory.newInstance();
TransformerHandler handler = factory.newTransformerHandler();
Transformer transformer = handler.getTransformer();
// 设置XML输出属性,编码为UTF-8,添加换行缩进
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
// 绑定输出流到目标文件
FileOutputStream fos = new FileOutputStream(outputFile);
StreamResult result = new StreamResult(fos);
handler.setResult(result);
// 开始创建XML文档,依次触发各节点事件
handler.startDocument();
AttributesImpl attributes = new AttributesImpl();
// 创建根节点user_list
handler.startElement("", "", "user_list", attributes);
// 创建第一个user子节点,添加id属性
attributes.clear();
attributes.addAttribute("", "", "id", "", "1");
handler.startElement("", "", "user", attributes);
// 添加name子节点和内容
handler.startElement("", "", "name", attributes);
handler.characters("张三".toCharArray(), 0, "张三".length());
handler.endElement("", "", "name");
// 添加age子节点和内容
handler.startElement("", "", "age", attributes);
handler.characters("22".toCharArray(), 0, "22".length());
handler.endElement("", "", "age");
handler.endElement("", "", "user");
// 创建第二个user子节点
attributes.clear();
attributes.addAttribute("", "", "id", "", "2");
handler.startElement("", "", "user", attributes);
handler.startElement("", "", "name", attributes);
handler.characters("李四".toCharArray(), 0, "李四".length());
handler.endElement("", "", "name");
handler.startElement("", "", "age", attributes);
handler.characters("25".toCharArray(), 0, "25".length());
handler.endElement("", "", "age");
handler.endElement("", "", "user");
// 结束根节点和文档
handler.endElement("", "", "user_list");
handler.endDocument();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}使用SAX解析XML文件
SAX解析XML需要自定义一个继承自DefaultHandler的处理类,重写对应的事件回调方法,再把该处理类绑定到XML解析器上执行解析操作。
自定义SAX解析处理器
以下是一个解析上述创建的用户列表XML的自定义处理器示例:
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 UserSAXHandler extends DefaultHandler {
// 存储解析得到的用户列表
private List<User> userList;
// 当前解析的用户对象
private User currentUser;
// 记录当前解析的标签名
private String currentTag;
public List<User> getUserList() {
return userList;
}
// 文档开始解析时初始化用户列表
@Override
public void startDocument() throws SAXException {
super.startDocument();
userList = new ArrayList<>();
}
// 遇到元素开始时回调
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
currentTag = localName;
if ("user".equals(localName)) {
// 遇到user标签时创建新的用户对象
currentUser = new User();
// 获取id属性值
String id = attributes.getValue("id");
currentUser.setId(id);
}
}
// 遇到元素内容时回调
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
super.characters(ch, start, length);
if (currentUser != null && currentTag != null) {
String content = new String(ch, start, length).trim();
if ("name".equals(currentTag)) {
currentUser.setName(content);
} else if ("age".equals(currentTag)) {
currentUser.setAge(content);
}
}
}
// 遇到元素结束时回调
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
super.endElement(uri, localName, qName);
if ("user".equals(localName)) {
// user标签结束时将当前用户加入列表
userList.add(currentUser);
currentUser = null;
}
currentTag = null;
}
// 文档解析结束时回调
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
}解析操作的执行代码
完成自定义处理器后,通过SAXParserFactory获取解析器,绑定处理器执行解析:
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public class SAXParseXMLUtil {
public static void parseXML(File xmlFile) {
try {
// 获取SAXParserFactory实例
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
// 创建自定义处理器
UserSAXHandler handler = new UserSAXHandler();
// 执行解析,传入文件流和处理器
FileInputStream fis = new FileInputStream(xmlFile);
parser.parse(fis, handler);
fis.close();
// 输出解析结果
List<User> users = handler.getUserList();
for (User user : users) {
Log.d("SAX_PARSE", "用户ID:" + user.getId() + ",姓名:" + user.getName() + ",年龄:" + user.getAge());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}对应的User实体类
解析用到的实体类定义如下:
public class User {
private String id;
private String name;
private String age;
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;
}
}开发注意事项
- SAX解析是顺序执行的,不能像DOM解析那样随机访问XML节点,如果需要频繁查询修改XML内容,建议选择其他解析方式
- 创建XML时如果内容包含特殊字符,比如<、&等,需要提前做转义处理,避免生成的XML格式错误
- 解析大文件时不要在回调方法里做耗时操作,避免阻塞解析线程,必要时可以切换到子线程处理解析逻辑
- 自定义Handler里的临时变量要注意重置,避免上一次解析的残留数据影响后续结果
通过上述内容,开发者可以完整掌握在Android中使用SAX方式创建和解析XML文件的方法,根据实际业务场景选择合适的XML处理方案,提升应用的性能和稳定性。