Java StAX

更新于 2025-12-28

Jakob Jenkov 2014-05-21

Java 的 StAX(Streaming API for XML)是一种用于解析 XML 流的 API,与 SAX API 类似。StAX 与 SAX 的主要区别在于:

  • StAX 是“拉取式”(pull)API,而 SAX 是“推送式”(push)API。
  • StAX 支持 XML 的读取和写入,而 SAX 只能读取 XML。

支持读写 vs. 仅支持读取的区别显而易见。但“拉取式”和“推送式”API 的区别则不那么直观,因此本文将对此进行详细说明。


“拉取式” vs. “推送式” API

SAX 是推送式 API

SAX 是一种推送式(push)风格的 API。这意味着 SAX 解析器会遍历整个 XML 文档,并在遍历过程中调用您提供的处理器(handler)对象中的方法。

例如,当 SAX 解析器遇到一个 XML 元素的开始标签时,它会调用您 handler 对象中的 startElement 方法。换句话说,解析器主动将 XML 中的信息“推送”到您的对象中,因此被称为“推送式”API。这种模式也常被称为“事件驱动”(event-driven)API —— 您的 handler 对象会在 XML 文档中发现“有趣内容”(如元素、文本、注释等)时收到事件通知。

下图展示了 SAX 解析器的工作方式:

graph LR A[SAX Parser] --> B[Your App]

StAX 是拉取式 API

StAX 则是一种拉取式(pull)风格的 API。这意味着您需要自己控制解析器在 XML 文件中的移动,就像使用标准的 Iterator 或 JDBC 的 ResultSet 一样。每当您“拉取”到下一个 XML 项(item)时,就可以通过解析器访问该项的相关信息(如元素、文本、注释等)。

下图展示了 StAX 解析器的工作方式:

graph LR A[Your App] --> B[StAX Parser]

实际上,StAX 提供了两种不同的读取器(reader)API:

  • 迭代器式(Iterator-style)读取器
  • 游标式(Cursor-style)读取器

它们分别类似于使用 IteratorResultSet 的方式。


迭代器式读取器(XMLEventReader)

迭代器式读取器在调用 nextEvent() 时会返回一个 XML 事件对象(XMLEvent)。通过该对象,您可以判断当前事件的类型(如开始元素、文本、注释等)。这个事件对象是不可变的(immutable),可以传递给应用程序的其他部分。而且,在继续遍历下一个事件时,您仍然可以保留对之前事件对象的引用。

这与遍历集合时使用 Iterator 非常相似 —— 只不过这里遍历的是 XML 事件。

示例代码如下:

XMLEventReader reader = ...;
while(reader.hasNext()){
    XMLEvent event = reader.nextEvent();
    if(event.getEventType() == XMLEvent.START_ELEMENT){
        StartElement startElement = event.asStartElement();
        System.out.println(startElement.getName().getLocalPart());
    }
    // ... 处理更多事件类型 ...
}

游标式读取器(XMLStreamReader)

游标式读取器在调用 next()不会返回事件对象,而是将内部“游标”移动到 XML 流中的下一个事件。然后,您可以直接在读取器上调用方法来获取当前事件的信息。

这种方式非常类似于使用 JDBC 的 ResultSet:您通过 next() 移动到下一行,再通过 getString()getLong() 等方法获取当前行的数据。

示例代码如下:

XMLStreamReader streamReader = ...;
while(streamReader.hasNext()){
    int eventType = streamReader.next();
    if(eventType == XMLStreamReader.START_ELEMENT){
        System.out.println(streamReader.getLocalName());
    }
    // ... 处理更多事件类型 ...
}

两种读取器的对比

  • 迭代器式 API 的优势在于:您可以保留对之前事件对象的引用。
  • 游标式 API 的优势在于:内存效率更高,性能更优。

因此:

  • 如果您的应用需要保留历史事件或结构更清晰,推荐使用 迭代器式 API
  • 如果追求极致性能和低内存占用,则应选择 游标式 API

这两种 API 都将在后续文章中详细介绍(见页面右侧目录)。


Java 中的 StAX 实现

截至本文撰写时(Java 6),JDK 仅包含 StAX 的接口并未内置具体实现。但有一个广泛使用的标准实现,可在此了解:

👉 https://webreference.com/xml/processing/stax/