DOM解析XML内存占用大但支持随机访问,适合小文件及频繁查询修改;超几MB易OOM;parse()不接受路径字符串,应使用FileInputStream或getResourceAsStream。

DOM解析XML:内存占用大但随机访问方便
DOM会把整个XML加载进内存构建成树形结构,适合小文件、需反复查询或修改的场景。一旦XML超过几MB,OutOfMemoryError就很容易出现,尤其在容器环境里限制堆内存时。
常见错误是直接用DocumentBuilder.parse()传入文件路径字符串——它只接受InputStream或InputSource,传String会当URI处理,导致FileNotFoundException或404错误。
- 正确做法:用
new FileInputStream("config.xml")或getClass().getResourceAsStream("/config.xml") - 节点遍历别写
for (int i = 0; i 然后反复调<code>nodeList.item(i)——长度每次调用都重新算,性能差;应先存到局部变量 - 注意
Element和Text节点混在一起,getChildNodes()返回的NodeList包含空白文本节点,不加过滤会空指针
SAX解析XML:流式读取,适合大文件但只能单向遍历
SAX是事件驱动的,边读边触发startElement、characters、endElement回调,不建树,内存友好。但它不能回退、不能随机查节点,逻辑稍复杂。
典型翻车点是把解析逻辑全塞进characters()里处理文本内容——这个方法可能被多次调用(比如CDATA跨缓冲区),导致字段被截断或覆盖。
立即学习“Java免费学习笔记(深入)”;
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 必须用
StringBuilder缓存characters()的数据,等endElement()再统一处理 -
startElement()里的Attributes参数才是属性值来源,别去getAttribute()元素节点本身 - 如果XML带命名空间,记得在
SAXParserFactory上设setNamespaceAware(true),否则getLocalName()返回空
DOM4J:API顺手但要注意依赖冲突和编码陷阱
DOM4J封装比原生DOM简洁,支持XPath、流式写入,是很多老项目的事实标准。但它不是JDK自带,得引dom4j依赖;Maven里若同时有xml-apis旧版,容易和JDK内置的javax.xml.*打架,抛NoClassDefFoundError。
另一个高频坑是中文乱码:即使XML声明写了<?xml version="1.0" encoding="UTF-8"?>,DOM4J默认用系统编码读文件,Linux下可能是ISO-8859-1。
- 读文件务必用
new SAXReader().read(new FileInputStream("a.xml")),别用read("a.xml")字符串路径 - 写XML时用
outputter.setEncoding("UTF-8"),且XMLWriter构造时传new OutputStreamWriter(out, "UTF-8") - 用XPath查节点前,确认
document.getRootElement()不为空——有些XML根元素外还有DOCTYPE或注释,read()可能没按预期加载
选型关键看三点:文件大小、访问模式、项目约束
小配置文件(xml-apis是否排除掉。
没人提但常被忽略的是XML外部实体(XXE)风险——三种方式默认都开启DTD解析,如果XML来自不可信源,DocumentBuilder和SAXReader都得手动禁用:setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)。DOM4J还要额外关setFeature("http://xml.org/sax/features/external-general-entities", false)。

















