SAX(Simple API for XML)是Java中解析XML的常用方式之一,它采用事件驱动模型,在读取XML文档时依次触发开始文档、开始元素、字符数据、结束元素等回调方法。由于不需要将整个文档构建为树结构,SAX占用内存少,适合解析较大的XML文件。

SAX解析的基本流程
使用SAX解析XML一般需要以下步骤:创建SAXParserFactory,获取SAXParser对象,编写继承DefaultHandler的处理类,最后调用parse方法并传入XML源与处理器实例。
核心处理类说明
我们需要重写DefaultHandler中的几个方法:
- startDocument():文档开始解析时调用
- startElement():遇到元素开始标签时调用
- characters():读取元素内文本时调用
- endElement():遇到元素结束标签时调用
示例XML文件
假设有一个简单的用户数据文件users.xml,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<users>
<user id="1">
<name>张三</name>
<age>28</age>
</user>
<user id="2">
<name>李四</name>
<age>32</age>
</user>
</users>
Java代码实现
下面给出完整的SAX解析示例代码,演示如何输出每个用户的编号、姓名与年龄。
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 SAXDemo {
// 自定义处理器
static class UserHandler extends DefaultHandler {
private String currentElement = "";
private String userName = "";
private String userAge = "";
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) {
currentElement = qName;
if ("user".equals(qName)) {
// 读取id属性
System.out.println("用户ID:" + attributes.getValue("id"));
}
}
@Override
public void characters(char[] ch, int start, int length) {
String value = new String(ch, start, length).trim();
if (value.length() == 0) return;
if ("name".equals(currentElement)) {
userName = value;
} else if ("age".equals(currentElement)) {
userAge = value;
}
}
@Override
public void endElement(String uri, String localName, String qName) {
if ("user".equals(qName)) {
System.out.println("姓名:" + userName + ",年龄:" + userAge);
userName = "";
userAge = "";
}
currentElement = "";
}
}
public static void main(String[] args) throws Exception {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
UserHandler handler = new UserHandler();
// 解析本地文件,也可使用InputStream
parser.parse(new File("users.xml"), handler);
}
}
注意事项
在characters()方法中,解析器可能多次调用该方法返回同一段文本,因此建议在endElement()中统一处理数据。另外,若XML中包含命名空间,可通过qName或localName区分。对于需要随机访问节点的场景,SAX并不适合,此时应考虑DOM或StAX方式。
SAX适合顺序读取、内存敏感的场景,理解事件回调机制是掌握它的关键。
小结
通过DefaultHandler配合SAXParser,我们可以以极低的内存开销解析XML。掌握startElement、characters与endElement的协作方式,就能应对大多数流式XML读取需求。