StAX是Java SE 6+内置的标准XML流式处理API,介于DOM与SAX之间,支持拉取式读取(XMLStreamReader)和流式写入(XMLStreamWriter),核心接口位于javax.xml.stream包,无需额外依赖。

StAX解析器到底是什么
StAX(Streaming API for XML)不是某种独立工具或第三方库,而是 Java SE 6+ 内置的、标准的 XML 流式处理 API。它介于 DOM(全量加载内存)和 SAX(纯事件驱动、只读)之间:既支持按需拉取(pull-style),又允许写入;既可控,又轻量。
核心接口是 XMLStreamReader(读)和 XMLStreamWriter(写),都定义在 javax.xml.stream 包里。JDK 自带实现(com.sun.xml.internal.stream.XMLInputFactoryImpl 等),无需额外依赖。
用 XMLStreamReader 逐个读取 XML 元素
与 SAX 不同,StAX 由你主动调用 next() 或 nextTag() 推进解析位置,逻辑更直观,也更容易中断、跳过或条件处理。
常见错误是忽略命名空间或属性顺序,导致 getAttributeValue(null, "id") 返回 null —— 实际上该属性可能在默认命名空间下,或名字拼错。
-
next()总是前进一位,返回当前事件类型(如START_ELEMENT、CHARACTERS) -
nextTag()跳过空白和注释,只停在 START_ELEMENT 或 END_ELEMENT - 获取属性推荐用
getAttributeValue(namespaceURI, localName),而非靠索引 - 文本内容必须在
CHARACTERS事件后调用getText(),且要检查是否为空白(isWhiteSpace())
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader reader = factory.createXMLStreamReader(new FileInputStream("data.xml"));
while (reader.hasNext()) {
int event = reader.next();
if (event == XMLStreamConstants.START_ELEMENT) {
String name = reader.getLocalName();
if ("user".equals(name)) {
String id = reader.getAttributeValue(null, "id"); // 注意 null 表示无命名空间
System.out.println("Found user id=" + id);
}
} else if (event == XMLStreamConstants.CHARACTERS && !reader.isWhiteSpace()) {
System.out.println("Text: " + reader.getText());
}
}
reader.close();
用 XMLStreamWriter 写出格式化 XML
XMLStreamWriter 是“流式生成”的关键:不构建树,不缓存整段内容,边写边刷出。适合日志、导出、API 响应等场景。但默认不自动缩进,需手动控制换行和空格。
容易被忽略的是编码声明和命名空间前缀绑定——如果没调用 writeStartElement("ns", "item", "http://example.com/ns") 就直接写属性,会导致前缀未声明错误。
- 创建时传入
OutputStream,推荐包装为OutputStreamWriter并指定 UTF-8 - 用
writeStartElement()/writeEndElement()成对管理标签 - 属性必须在 START_ELEMENT 之后、END_ELEMENT 之前写,否则抛
XMLStreamException - 调用
writeCharacters("\n ")可模拟缩进,但非标准做法;真正生产环境建议用IndentingXMLStreamWriter(来自 Woodstox 或自定义装饰器)
XMLOutputFactory factory = XMLOutputFactory.newInstance();
XMLStreamWriter writer = factory.createXMLStreamWriter(
new OutputStreamWriter(System.out, StandardCharsets.UTF_8));
writer.writeStartDocument("UTF-8", "1.0");
writer.writeStartElement("root");
writer.writeAttribute("version", "2.0");
writer.writeStartElement("item");
writer.writeAttribute("id", "101");
writer.writeCharacters("Hello World");
writer.writeEndElement();
writer.writeEndElement();
writer.writeEndDocument();
writer.flush();
writer.close();
读写混合场景:边读边改再写入新文件
这是 StAX 最实用的模式之一,比如清洗 XML 中的敏感字段、升级 schema 版本、过滤特定节点。不能直接在原 XMLStreamReader 上修改,必须用 XMLStreamWriter 重建输出。
关键点在于状态跟踪:你得自己记住当前路径(如 /users/user[2]/email),否则无法判断是否该跳过或替换。没有 XPath 集成,也不能随机访问。
- 不要试图复用同一个
XMLStreamReader多次遍历 —— 它是单向流,不可重置 - 写入前确保目标
OutputStream已打开,且编码一致(尤其含中文时) - 异常处理必须包含
reader.close()和writer.close(),建议用 try-with-resources - 大文件下注意字符缓冲:
writeCharacters(String)比循环写单字符快得多
StAX 的“流式”本质决定了它不提供树结构、不支持 XPath 查询、也不维护父子关系。所有上下文逻辑都得你自己维护 —— 这既是自由,也是负担。










