什么是 DOM?
DOM (Document Object Model, 文档对象模型) 是一种用于 XML 和 HTML 的编程接口,它将整个 XML 文档读入内存,解析成一个由节点(Node)构成的树状结构。

DOM 的特点:
- 树状结构:XML 文档的每个部分(元素、属性、文本等)都是一个节点,这些节点组成了一个树。
- 一次性加载:解析器会读取整个 XML 文件并将其完整地加载到内存中。
- 随机访问:因为整个文档都在内存中,你可以通过节点树随意访问任何一部分数据,就像操作一个对象一样。
- 消耗内存大:对于非常大的 XML 文件,一次性加载到内存可能会导致性能问题甚至内存溢出(
OutOfMemoryError)。
准备工作:创建一个示例 XML 文件
我们创建一个名为 students.xml 的文件,作为我们解析的目标。
students.xml
<?xml version="1.0" encoding="UTF-8"?>
<students>
<student id="S001">
<name>张三</name>
<age>20</age>
<gender>男</gender>
</student>
<student id="S002">
<name>李四</name>
<age>22</age>
<gender>女</gender>
</student>
<student id="S003">
<name>王五</name>
<age>21</age>
<gender>男</gender>
<email>wangwu@example.com</email>
</student>
</students>
Java DOM 解析步骤
使用 Java DOM 解析 XML 主要分为以下几个步骤:

- 创建
DocumentBuilderFactory和DocumentBuilder:这是解析器的工厂和构建器。 - 解析 XML 文件,获取
Document对象:Document对象代表了整个 XML 文档的树形结构。 - 获取根节点:通过
Document对象获取 XML 的根元素。 - 遍历节点树:通过
getElementsByTagName()或getChildNodes()等方法获取子节点,并遍历它们。 - 提取节点数据:获取节点的名称、文本内容或属性值。
- 关闭资源:虽然
DocumentBuilder通常不需要显式关闭,但养成好习惯总是好的。
完整代码示例
下面是一个完整的 Java 类,它演示了如何读取 students.xml 文件并打印出所有学生的信息。
DomParserDemo.java
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
public class DomParserDemo {
public static void main(String[] args) {
// 1. 创建一个 DocumentBuilderFactory 实例
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
// 2. 创建一个 DocumentBuilder 实例
DocumentBuilder builder = factory.newDocumentBuilder();
// 3. 解析 XML 文件,获取 Document 对象
// 注意:请确保 students.xml 文件位于项目的根目录下,或者提供正确的文件路径
File xmlFile = new File("students.xml");
Document document = builder.parse(xmlFile);
// 4. 获取根节点 <students>
Element rootElement = document.getDocumentElement();
System.out.println("根节点名称: " + rootElement.getNodeName());
// 5. 获取所有名为 "student" 的节点列表
NodeList studentList = rootElement.getElementsByTagName("student");
System.out.println("\n--- 开始解析学生信息 ---");
// 6. 遍历 student 节点列表
for (int i = 0; i < studentList.getLength(); i++) {
// 获取每个 student 节点
Node studentNode = studentList.item(i);
// 确保节点是元素节点(避免处理文本节点等)
if (studentNode.getNodeType() == Node.ELEMENT_NODE) {
Element studentElement = (Element) studentNode;
// 获取 student 元素的 id 属性
String id = studentElement.getAttribute("id");
System.out.println("\n学生ID: " + id);
// 获取子节点 <name>, <age>, <gender>
// getElementsByTagName() 会从当前节点及其所有子节点中查找
NodeList childNodes = studentElement.getChildNodes();
for (int j = 0; j < childNodes.getLength(); j++) {
Node childNode = childNodes.item(j);
if (childNode.getNodeType() == Node.ELEMENT_NODE) {
Element childElement = (Element) childNode;
String nodeName = childElement.getNodeName();
String nodeValue = childElement.getTextContent().trim(); // 获取节点内的文本内容并去除首尾空格
System.out.println(nodeName + ": " + nodeValue);
}
}
}
}
System.out.println("\n--- 解析完成 ---");
} catch (Exception e) {
e.printStackTrace();
}
}
}
代码详解
-
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();- DOM 解析器是通过工厂模式创建的。
newInstance()方法会根据系统配置返回一个DocumentBuilderFactory的实例。
- DOM 解析器是通过工厂模式创建的。
-
DocumentBuilder builder = factory.newDocumentBuilder();
(图片来源网络,侵删)- 使用工厂实例创建一个具体的
DocumentBuilder,它负责实际的解析工作。
- 使用工厂实例创建一个具体的
-
File xmlFile = new File("students.xml");- 创建一个
File对象,指向你的 XML 文件。请确保文件路径正确,如果文件不在项目根目录,需要提供完整路径,"C:/data/students.xml"。
- 创建一个
-
Document document = builder.parse(xmlFile);- 这是核心步骤,
parse()方法读取并解析 XML 文件,返回一个Document对象,它代表了整个 XML 文档的内存模型。
- 这是核心步骤,
-
Element rootElement = document.getDocumentElement();getDocumentElement()方法获取文档的根元素,在这里就是<students>。
-
NodeList studentList = rootElement.getElementsByTagName("student");getElementsByTagName()方法返回一个NodeList,其中包含了所有指定标签名的节点,这里我们获取了所有的<student>节点。
-
遍历和提取数据
for (int i = 0; i < studentList.getLength(); i++): 遍历每个<student>节点。if (studentNode.getNodeType() == Node.ELEMENT_NODE): XML 文件中除了元素节点,还有文本节点(如换行、空格)、注释节点等,这个判断确保我们只处理元素节点。Element studentElement = (Element) studentNode;: 将Node强制转换为Element,这样才能调用Element类特有的方法,如getAttribute()。String id = studentElement.getAttribute("id");:getAttribute()方法用于获取元素的属性值。childElement.getTextContent():getTextContent()是获取一个节点及其所有子节点的文本内容的推荐方法,非常方便,对于<name>张三</name>,它会返回 "张三"。
运行结果
当你运行 DomParserDemo.java 时,控制台将输出以下内容:
根节点名称: students
--- 开始解析学生信息 ---
学生ID: S001
name: 张三
age: 20
gender: 男
学生ID: S002
name: 李四
age: 22
gender: 女
学生ID: S003
name: 王五
age: 21
gender: 男
email: wangwu@example.com
--- 解析完成 ---
DOM 的优缺点总结
优点:
- 易于理解和使用:树状结构直观,适合处理小型到中型的 XML 文件。
- 随机访问:可以随时访问文档中的任何节点,无需按顺序遍历。
- API 成熟稳定:是 Java 标准库的一部分,无需额外依赖。
缺点:
- 内存消耗大:必须将整个 XML 文档加载到内存中,对于大文件(几百MB或GB级别)会导致性能瓶颈和内存问题。
- 解析速度相对较慢:因为需要构建完整的树,所以启动时间比流式解析器(如 SAX)长。
何时使用 DOM?
- XML 文件较小,可以完全加载到内存中。
- 你需要频繁地、随机地访问 XML 文档的不同部分。
- 你需要修改 XML 文档并重新写回文件(DOM 也支持修改和写入)。
如果你的 XML 文件非常大,或者你只需要从头到尾顺序读取一次数据,那么应该考虑使用 SAX (Simple API for XML) 或 StAX (Streaming API for XML) 解析器,它们是事件驱动的,内存占用非常小。
