XML介绍
一、XML 核心格式规则
XML(可扩展标记语言)作为结构化数据存储与传输的经典格式,其严格的语法规则是解析成功的前提。掌握以下核心规范,可避免 90% 的解析报错。
1. 文档结构三要素
- 文档声明:可选但推荐置于首行,定义版本与编码,格式为<?xml version="1.0" encoding="UTF-8"?>。缺失编码声明可能导致中文乱码,需与文件实际编码保持一致。
- 唯一根元素:所有节点必须嵌套在单个根元素内,这是 XML 的强制要求。如下错误示例因两个根节点会触发解析失败:
<!-- 错误示例:多个根节点 -->
<users><user>张三</user></users>
<products><product>手机</product></products>
正确写法需用统一根节点包裹:
<!-- 正确示例:唯一根节点 -->
<data>
<users><user>张三</user></users>
<products><product>手机</product></products>
</data>
- 树状嵌套结构:子节点需完全嵌套在父节点内,禁止交叉嵌套。合理的多层嵌套如下:
<school> <!-- 根节点 -->
<class id="1"> <!-- 子节点 -->
<student> <!-- 孙节点 -->
<name>张三</name> <!-- 曾孙节点 -->
</student>
</class>
</school>
2. 元素与属性规范
- 元素规则:需成对出现(如<title></title>),空元素可用自闭合形式(<br/>),且名称区分大小写(<Book>与<book>是不同元素)。
- 属性规则:作为元素的附加信息,需用单 / 双引号包裹值(如id="101"),同一元素内属性名称不可重复。属性适合存储元数据,核心数据建议放在元素文本中。
3. 特殊字符处理
文本中的<、&等特殊字符需通过实体引用(如<代指<,&代指&)转义,或使用CDATA 区直接包含原始内容:
<!-- 实体引用示例 -->
<price>5 < 10</price>
<!-- CDATA区示例 -->
<description><![CDATA[价格<50&库存>100]]></description>
二、四大解析技术对比
XML 解析器是连接文档与程序的桥梁,不同解析技术适用于不同场景。主流方案可分为底层接口(DOM/SAX)与 Java 高级封装(JDOM/DOM4J)两类。
1. 底层核心解析器
特性 | DOM | SAX |
解析模式 | 树状模型(加载全文档构建节点树) | 事件驱动(逐行扫描触发事件) |
内存占用 | 高(需存储整棵树) | 低(无需保留完整结构) |
操作能力 | 支持增删改查与随机访问 | 仅支持读取,无随机访问 |
适用场景 | 小文档、需修改数据、频繁查询 | 大文档、仅读取部分数据 |
编程难度 | 简单(直接操作节点树) | 复杂(需自定义事件处理器) |
2. Java 高级封装解析器
- JDOM:专为 Java 设计,摒弃接口仅用具体类,大量复用 Collections 类,降低开发门槛。但灵活性不足,且自身不包含解析器,需依赖 SAX2 引擎。
- DOM4J:JDOM 的进阶分支,支持 XPath 查询、XML Schema 验证,提供接口化设计兼具灵活性与性能。是目前 Java 生态的主流选择,被 Sun JAXM 等框架采用。
3. 选型决策树
三、Java 中 DOM4J 解析 XML 文档
以解析图书信息 XML 为例,展示 DOM4J 的核心用法(需导入 dom4j.jar 依赖)。
1. 待解析 XML 文档(books.xml)
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book id="101" category="编程">
<title>XML 教程</title>
<price>59.9</price>
</book>
<book id="102" category="文学">
<title>百年孤独</title>
<price>39.8</price>
</book>
</bookstore>
2. DOM4J 解析代码
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.util.Iterator;
public class XmlParser {
public static void main(String[] args) throws DocumentException {
// 1. 创建解析器
SAXReader reader = new SAXReader();
// 2. 加载文档
Document doc = reader.read("books.xml");
// 3. 获取根节点
Element root = doc.getRootElement();
// 4. 遍历子节点
Iterator<Element> it = root.elementIterator("book");
while (it.hasNext()) {
Element book = it.next();
// 获取属性值
String id = book.attributeValue("id");
String category = book.attributeValue("category");
// 获取子元素文本
String title = book.elementText("title");
String price = book.elementText("price");
// 输出结果
System.out.printf("图书ID:%s,分类:%s,标题:%s,价格:%s%n",
id, category, title, price);
}
}
}
3. 输出结果
图书ID:101,分类:编程,标题:XML 教程,价格:59.9
图书ID:102,分类:文学,标题:百年孤独,价格:39.8
四、XML 的定位
尽管 JSON 因轻量性在 API 交互中占据主导,但 XML 仍不可替代,二者核心差异如下:
维度 | XML | JSON |
扩展性 | 支持命名空间、Schema 验证,扩展性强 | 无命名空间,结构简单 |
可读性 | 标签语义清晰,适合复杂层级 | 键值对简洁,适合简单数据 |
冗余度 | 高(标签重复) | 低(节省带宽) |
适用场景 | 配置文件(如 Spring 配置)、SOAP 协议 | 前端数据交互、RESTful API |
最佳实践:系统配置与复杂结构化数据用 XML,轻量级数据交换用 JSON,二者可通过工具(如 Jackson)相互转换。
五、解析 XML 的常见问题与解决方案
- 编码不一致报错:确保文档声明的 encoding(如 UTF-8)与文件实际编码、解析器读取编码一致。
- 未找到根节点:检查是否存在多个根元素,或文档声明与根节点间有空白字符。
- 属性值未加引号:严格遵循属性值引号包裹规则,单双引号不可混用遗漏。
- 大文档 OOM:放弃 DOM 解析,改用 SAX 或 DOM4J 的事件模式逐行处理。
