JDOM2是一个专门为Java设计的XML解析库,它把XML文档封装成直观的树形对象模型,开发者可以通过Java集合风格的API来访问元素、属性和文本内容。与W3C DOM不同,JDOM2没有沿用那些繁琐的节点类型判断,而是直接使用Element、Attribute、Text这些具体类,这让代码量大幅减少。如果你的项目里需要处理XML配置文件、数据交换格式或者简单的序列化场景,JDOM2是个值得优先考虑的选择。

环境准备与第一个JDOM2程序
使用JDOM2之前,需要先把它添加到项目依赖中。如果你用的是Maven,在pom.xml里加入下面这段配置即可。JDOM2的groupId是org.jdom,artifactId是jdom2,目前比较常见的版本是2.0.6.1。如果你使用Gradle,也只需一行implementation声明。对于不用构建工具的项目,可以下载jdom2的jar包并手动添加到classpath。
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom2</artifactId>
<version>2.0.6.1</version>
</dependency>
添加完依赖后,先写一个读取XML文件并打印根元素名称的小程序。假设本地有一个名为books.xml的文件,内容大致如下:根元素是<books>,里面包含两个<book>子元素,每个book都有id属性和title子元素。我们需要用SAXBuilder来解析这个文件,SAXBuilder是JDOM2中最常用的解析入口,它底层使用SAX解析器,但把结果构建成JDOM2的Document对象。代码里要注意捕获JDOMException和IOException,因为XML格式错误或文件不存在都会抛出异常。
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import java.io.File;
import java.io.IOException;
public class ReadXmlDemo {
public static void main(String[] args) {
SAXBuilder builder = new SAXBuilder();
try {
Document doc = builder.build(new File("books.xml"));
Element root = doc.getRootElement();
System.out.println("根元素名称: " + root.getName());
} catch (JDOMException | IOException e) {
e.printStackTrace();
}
}
}
运行后会输出根元素名称books。这里SAXBuilder的build方法有好几个重载版本,可以接受File、InputStream、Reader、URL等不同输入源。对于大文件,SAXBuilder比DOM解析器更节省内存,因为它在构建树的过程中可以进行一些优化,但它仍然会在内存中保留完整的文档树,所以不适合处理超大XML。
遍历XML节点与属性操作
拿到根元素之后,最常见的需求就是遍历子元素、读取属性值以及获取元素内的文本。JDOM2提供了getChildren方法返回一个List<Element>,可以直接用for-each循环处理。如果要获取某个元素的文本内容,使用getText方法,如果元素本身混合了子元素和文本,getText只会返回直接文本节点,这时需要getContent方法。对于属性,getAttributeValue("属性名")是最方便的方式,如果属性不存在会返回null,也可以传入默认值作为第二个参数。
下面这段代码遍历books.xml中每一个book元素,打印出id属性和title子元素的文本。注意getChild("title")返回的是第一个匹配的子元素,如果title不存在会返回null,调用getText之前最好做空判断。对于需要处理命名空间的场景,JDOM2也支持通过Namespace对象来访问,但普通配置文件一般用不到。
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;
import java.io.File;
import java.util.List;
public class TraverseXmlDemo {
public static void main(String[] args) throws Exception {
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(new File("books.xml"));
Element root = doc.getRootElement();
List<Element> books = root.getChildren("book");
for (Element book : books) {
String id = book.getAttributeValue("id");
Element titleElement = book.getChild("title");
String title = titleElement != null ? titleElement.getText() : "无标题";
System.out.println("ID: " + id + ", 标题: " + title);
}
}
}
JDOM2还提供了一种更灵活的遍历方式,通过迭代器模式来处理深层嵌套的XML。例如root.getDescendants()可以获取所有后代节点,配合过滤器可以筛选出特定类型的节点。如果只想拿到所有名为title的元素,可以使用root.getDescendants(new ElementFilter("title")),返回的迭代器里只包含匹配的元素。这种方式在结构不固定的XML中很有用。
创建XML文档与写出到文件
除了读取,用JDOM2构建XML文档同样简单。你可以从零开始创建根元素,然后不断添加子元素和属性,最后用XMLOutputter把Document输出到文件或控制台。XMLOutputter默认会进行基本的格式化,也可以设置缩进、编码等参数。新建XML时,注意要为Document设置根元素,否则输出会抛出异常。
下面的代码创建了一个包含两个book元素的XML文档,每个book有id属性和title、author子元素,然后将其写出到output.xml文件。输出时可以指定编码为UTF-8,并设置Format.getPrettyFormat()来让生成的XML带缩进和换行,方便阅读。如果你需要输出紧凑格式,可以使用Format.getRawFormat()。
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import java.io.FileWriter;
import java.io.IOException;
public class WriteXmlDemo {
public static void main(String[] args) throws IOException {
Element root = new Element("books");
Document doc = new Document(root);
Element book1 = new Element("book");
book1.setAttribute("id", "1001");
book1.addContent(new Element("title").setText("Java编程思想"));
book1.addContent(new Element("author").setText("Bruce Eckel"));
root.addContent(book1);
Element book2 = new Element("book");
book2.setAttribute("id", "1002");
book2.addContent(new Element("title").setText("Effective Java"));
book2.addContent(new Element("author").setText("Joshua Bloch"));
root.addContent(book2);
XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
outputter.setEncoding("UTF-8");
outputter.output(doc, new FileWriter("output.xml"));
System.out.println("XML文件已生成");
}
}
在构建元素内容时,addContent方法可以接受字符串、Element、Text等多种类型。setText方法会先清除原有内容再添加文本,适合简单场景。如果元素内需要混合多个子元素和文本,建议分别创建Text对象和Element对象然后依次addContent。另外,JDOM2的Element类实现了Cloneable接口,可以通过clone方法复制节点,这在需要生成相似结构时能减少重复代码。
使用XPath快速定位节点
当XML结构较深或需要按条件筛选节点时,手动遍历会很啰嗦。JDOM2内置了XPath支持,可以通过XPathFactory和XPathExpression来执行XPath表达式。XPath表达式可以精确定位到元素、属性甚至文本节点,比如//book[@id='1001']表示查找id属性为1001的book元素。使用JDOM2的XPath需要额外引入jaxen依赖,因为JDOM2的XPath实现基于Jaxen库,不引入会报ClassNotFoundException。
下面代码演示了如何用XPath查找所有title元素的文本,以及获取特定属性的值。注意XPathExpression的evaluateFirst方法返回第一个匹配的节点,evaluate方法返回所有匹配节点的列表。如果表达式返回的是属性值,可以直接用字符串形式接收。添加jaxen依赖时,Maven坐标是jaxen:jaxen,版本1.2.0即可。
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;
import org.jdom2.xpath.XPathFactory;
import org.jdom2.xpath.XPathExpression;
import java.io.File;
import java.util.List;
public class XPathDemo {
public static void main(String[] args) throws Exception {
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(new File("books.xml"));
XPathFactory xpf = XPathFactory.instance();
XPathExpression<Element> expr = xpf.compile("//title", Filters.element());
List<Element> titles = expr.evaluate(doc);
for (Element title : titles) {
System.out.println("标题: " + title.getText());
}
XPathExpression<String> idExpr = xpf.compile("//book/@id", Filters.attribute());
List<String> ids = idExpr.evaluate(doc);
System.out.println("所有book的id: " + ids);
}
}
XPath在JDOM2中使用时需要注意类型安全。通过Filters.element()或Filters.attribute()可以指定返回的节点类型,避免强制转换。如果XPath表达式写错了,编译时会抛出异常,所以建议把XPath字符串定义成常量以便维护。对于复杂的XML查询,XPath比手动递归遍历要清晰得多,但引入jaxen依赖会增加项目体积,小型项目可以权衡使用。
JDOM2的整体设计遵循了Java集合框架的思维,让XML操作变得像操作List和Map一样自然。虽然它不像DOM那样遵循跨语言标准,但在纯Java环境中,JDOM2的代码可读性和开发效率都明显优于DOM和SAX。文中的示例完整覆盖了读取、遍历、创建、写出和XPath查询这几个核心环节,你可以把代码保存下来作为日常处理的模板。当需要处理更多高级特性时,比如命名空间、CDATA、注释节点,JDOM2的API同样提供了相应支持,查阅官方Javadoc即可找到用法。
JDOM2Java XML解析JDOM2入门教程修改时间:2026-09-17 08:45:07