5月28日 03:47

XML 解析中 DOM 和 SAX 有什么区别?

DOM 把整个 XML 一次性加载到内存建树,SAX 逐行读、遇到标签就触发回调。所以 DOM 能随机访问、能改,但吃内存;SAX 省内存、速度快,但只能顺序读、不能改。面试里一般答到"一个树一个事件驱动"就算到位,但追问肯定会问更细。

追问

DOM 和 SAX 的内存差距到底有多大?

解析一个 100MB 的 XML,DOM 可能吃掉 300-500MB 内存(树节点的对象开销远大于原始文本),SAX 基本只占几 KB 的缓冲区。大文件用 DOM 直接 OOM 是真实生产事故,不是理论风险。

StAX 和 SAX 有什么区别?为什么有了 SAX 还要 StAX?

SAX 是推模型——解析器主动推事件给你,你没法控制解析节奏。StAX 是拉模型——你调用 next() 主动拉下一个事件,想停就停,想跳就跳。实际开发中 StAX 更灵活,代码也更好写(不用写一堆回调)。JDK 6 开始 StAX 就是 JAXP 的一部分了。

实际项目里怎么选?

场景选择原因
配置文件(几十 KB)DOM / Dom4j小文件内存不是问题,随机访问方便
大日志文件(几百 MB+)SAX / StAX流式处理不爆内存
需要修改 XML 再写回DOMSAX 只读,改不了
只提取少数字段SAX / StAX不用为几个字段加载整棵树

JAXB 还在用吗?

Java 9 标记废弃,Java 11 正式移除(从 JDK 里删了)。现在要用得手动加 jakarta.xml.bind 依赖。新项目如果要做 XML-对象映射,Jackson 的 XML 模块比 JAXB 好用。

DOM 解析有什么常见坑?

  1. 编码问题:XML 声明的 encoding 和文件实际编码不一致,直接乱码或抛异常
  2. 空白节点:格式化缩进会产生大量 #text 空白节点,遍历时要 getNodeType() 过滤,否则逻辑全乱
  3. 命名空间:带命名空间的 XML 必须用 getElementsByTagNameNS(),用错方法查不到元素
  4. 实体注入:外部实体引用(XXE)是安全漏洞,解析时必须禁用:factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)

写段代码

StAX 拉式解析,对比上面 SAX 的回调写法,感受下代码简洁度的差距:

java
XMLStreamReader reader = XMLInputFactory.newInstance() .createXMLStreamReader(new FileInputStream("data.xml")); while (reader.hasNext()) { if (reader.next() == START_ELEMENT && reader.getLocalName().equals("title")) { System.out.println(reader.getElementText()); } }
标签:XML