DOM4J 是需显式引入的 Java 开源 XML 库,以简洁 API 支持读取、XPath 查询、动态修改和格式化输出,但需注意编码设置、命名空间处理、依赖冲突及安全配置等细节。

DOM4J 的定位很清晰:比原生 DOM 更轻量,比 SAX 更易用,比 JDOM 更活跃(尤其在老项目中仍广泛存在)。 它对中文字符、命名空间、大文件流式处理的支持也相对成熟,但要注意——它默认不开启 DTD 或 XSD 验证,若 XML 含外部实体或恶意引用,需手动禁用。
如何添加 dom4j 依赖并避免常见 classpath 错误
使用 Maven 时,推荐用最新稳定版(截至 2024 年主流是 2.1.4),注意不要混用旧版(如 1.6.1)和新包名冲突的 snapshot 版本:
org.dom4j dom4j 2.1.4
常见错误包括:
- 仅加了
dom4j.jar却没带jaxen(XPath 支持依赖),导致document.selectNodes("//item")报NoClassDefFoundError: org/jaxen/JaxenException - Spring Boot 2.5+ 项目中,若已引入
spring-boot-starter-web,其内嵌的xmlpull和xpp3可能与 dom4j 冲突,建议排除:xpp3 - Android 项目慎用——dom4j 依赖部分 Java SE 类(如
javax.xml.parsers.DocumentBuilder),在低版本 Android 上会 ClassNotFound
用 SAXReader 快速加载 XML 并安全处理编码与异常
SAXReader 是 dom4j 最常用的入口类,但它不是 SAX 实现,而是封装了底层解析器(默认用 Xerces)。关键点在于:它默认按系统编码读取,遇到 UTF-8 BOM 或 GBK 文件极易乱码。
正确做法是显式指定输入源和编码:
立即学习“Java免费学习笔记(深入)”;
SAXReader reader = new SAXReader();
reader.setEncoding("UTF-8"); // 必须在 read() 前设置
Document doc = reader.read(new FileInputStream("config.xml")); // 不推荐:未指定编码
// 推荐写法:
Document doc = reader.read(new InputSource(new FileInputStream("config.xml")) {{
setEncoding("UTF-8");
}});
更健壮的方式是用 InputStreamReader 包装:
try (InputStream is = getClass().getResourceAsStream("/data.xml");
Reader readerStream = new InputStreamReader(is, StandardCharsets.UTF_8)) {
Document doc = new SAXReader().read(readerStream);
}
注意:SAXReader.read(File) 会自动探测编码(依赖文件 BOM),但不可靠;read(String)(路径字符串)默认用系统编码,Windows 上极易出错。
用 XPath 提取节点时绕开命名空间陷阱
XML 带命名空间(如 )时,直接写 //item 会返回空列表——这是 dom4j 用户最常卡住的点。
解决方法有两种:
- 注册命名空间前缀:
MapnsMap = Map.of("r", "http://purl.org/rss/1.0/"); doc.valueOf("//r:item/title", nsMap); - 忽略命名空间(适合只读场景):
reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); reader.setFeature("http://xml.org/sax/features/namespaces", false);
另外,selectSingleNode() 返回 Node,需强转为 Element 才能调用 getText();而 valueOf() 直接返回字符串,更安全:
// ❌ 危险:可能 NPE
String title = ((Element) doc.selectSingleNode("//item/title")).getText();
// ✅ 推荐
String title = doc.valueOf("//item/title"); // 空路径返回空字符串,不抛 NPE
修改 XML 结构后写回文件的注意事项
dom4j 修改文档后,用 XMLWriter 输出时,默认不缩进、不换行、不声明编码,生成的 XML 难以调试。
要输出可读格式,必须配置 OutputFormat:
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("UTF-8");
format.setIndentSize(2);
try (XMLWriter writer = new XMLWriter(new FileWriter("output.xml"), format)) {
writer.write(doc);
}
容易忽略的点:
-
format.setNewLineAfterDeclaration(true)控制是否在后换行 - 若 XML 中有 CDATA 段,需设
format.setExpandEmptyElements(false),否则可能被改写成(看似一样,但某些解析器对空格敏感) - 写入时若目标文件被其他进程占用,
FileWriter默认覆盖而非报错,建议先Files.deleteIfExists(Paths.get("output.xml"))










