1. 认识 XML
尽管今天 JSON 已是标准,在 Java 世界里仍有大量遗留代码,因此你有时仍会遇到 XML。了解它很有用。 XML(eXtensible Markup Language,可扩展标记语言)是一种用于存储与交换结构化数据的文本格式。它常用于配置、程序间交换、数据存储,甚至用于对象序列化。
XML 文档结构的基本要素:
标签(元素):
位于 < 与 > 之间的内容。每个标签都有开始(<tag>)与结束(</tag>),或为自闭合(<tag/>)。
属性:
标签内部的附加参数。
示例: <user name="瓦夏" age="25"/>
文本节点:
位于标签之间的文本。
示例:<greeting>你好,世界!</greeting>
简单 XML 文档示例
<?xml version="1.0" encoding="UTF-8"?>
<users>
<user name="瓦夏" age="25">你好!</user>
<user name="卡佳" age="30"/>
</users>
这里:
- <users> — 根元素。
- <user> — 带有 name 与 age 属性的元素,第一个用户还有文本内容。
2. 关键概念
序言(prolog):
文件开头的一行用于指明 XML 版本与编码。
示例: <?xml version="1.0" encoding="UTF-8"?>
元素:
XML 的基本构建块。
示例:<book>...</book>
属性:
位于开始标签中的参数。
示例: <book title="Java" author="伊万诺夫"/>
注释:
与 HTML 类似,写在 <!-- ... --> 之间。
示例:<!-- 这是注释 -->
CDATA 段:
允许插入不会被当作 XML 解析的文本(例如包含 <、& 等符号)。
示例:
<script><![CDATA[
if (a < b && b > 0) { ... }
]]></script>
3. 为什么在 XML 中需要命名空间(namespaces)
问题:名称冲突
在大型 XML 文档中,常会出现名称相同但含义不同的标签。例如,你可能同时有用于 HTML 的 <table>,以及你业务逻辑(例如数据库)中的 <table>。如何区分它们的含义?
没有命名空间:
<root>
<table>
<row>...</row>
</table>
<table>
<column>...</column>
</table>
</root>
这里无法明确每个 <table> 的含义。
解决方案:命名空间
命名空间(namespace)是一种“标记”元素与属性的方式,用来避免名称冲突,并清晰地区分不同标签的语义。
- 每个命名空间都是唯一的 URI(通常看起来像链接,但它只是一个标识符)。
- 即使名称相同,属于不同命名空间的元素与属性也被视为不同。
优点:
- 不同标准与模式之间不会发生名称冲突。
- 可以在同一文档中合并来自不同来源的数据。
- 每个标签属于哪个“词汇表”一目了然。
4. 使用命名空间:声明与应用
如何声明命名空间
在某个元素的开始标签中使用特殊属性 xmlns(XML Namespace):
- 无前缀:xmlns="URI" —— 为所有嵌套元素声明默认命名空间。
- 带前缀:xmlns:prefix="URI" —— 用前缀(短名)声明命名空间,以便在标签中使用。
声明与使用命名空间的示例
<root xmlns:h="http://www.w3.org/TR/html4/"
xmlns:f="http://www.w3schools.com/furniture">
<h:table>
<h:tr>
<h:td>单元格 1</h:td>
<h:td>单元格 2</h:td>
</h:tr>
</h:table>
<f:table>
<f:name>桌子</f:name>
<f:width>80</f:width>
<f:length>120</f:length>
</f:table>
</root>
这里:
- xmlns:h="..." —— 为 HTML 表格声明前缀 h。
- xmlns:f="..." —— 为“家具”声明前缀 f。
- <h:table> 与 <f:table> —— 即使名称相同,也是不同的元素。
如何使用命名空间
- 声明: 在根元素或任何元素上:xmlns:prefix="URI"
- 应用: 在元素或属性名称前加前缀与冒号:<prefix:element>...</prefix:element>
默认命名空间
如果仅声明 xmlns="URI",则所有不带前缀的元素都属于该命名空间。
<books xmlns="http://example.com/books">
<book>...</book>
</books>
5. 实战:创建一个包含多个命名空间的简单 XML 文档
我们来创建一个示例 XML 文档,其中使用两个命名空间:一个用于 HTML,一个用于“家具”。
<?xml version="1.0" encoding="UTF-8"?>
<root xmlns:h="http://www.w3.org/TR/html4/"
xmlns:f="http://www.w3schools.com/furniture">
<h:table>
<h:tr>
<h:td>单元格 1</h:td>
<h:td>单元格 2</h:td>
</h:tr>
</h:table>
<f:table>
<f:name>桌子</f:name>
<f:width>80</f:width>
<f:length>120</f:length>
</f:table>
</root>
这里发生了什么:
- 在根元素上声明了两个命名空间:h 与 f。
- 所有带前缀 h: 的元素属于 HTML 表格。
- 所有带前缀 f: 的元素属于“家具”。
6. 常见错误
错误 1:忘记声明前缀
<root>
<h:table>...</h:table>
</root>
结果: XML 解析器会报错:The prefix 'h' for element 'h:table' is not bound.
错误 2:未使用命名空间的同名元素
<root>
<table>...</table>
<table>...</table>
</root>
结果: 无法区分哪个 <table> 属于什么。
错误 3:错误使用前缀
<root xmlns:h="http://www.w3.org/TR/html4/">
<h:table>...</h:table>
<f:table>...</f:table> <!-- 错误:未声明前缀 f -->
</root>
结果: 解析器错误:The prefix 'f' for element 'f:table' is not bound.
GO TO FULL VERSION