XML 格式验证:DTD 与 XML Schema 详解
XML(可扩展标记语言)的灵活性使其广泛应用于数据交换和存储,但这种灵活性也带来了格式混乱的风险。为确保 XML 文档的结构合法性和数据有效性,需要通过语义约束机制进行验证。目前主流的 XML 验证方式有两种:DTD(文档类型定义) 和XML Schema(XML 模式)。
DTD(Document Type Definition,文档类型定义)
DTD 是最早的 XML 语义约束标准,通过定义元素、属性、实体等规则,规范 XML 文档的结构。它语法简单,易于理解,但功能有限。
DTD 的引入方式
DTD 可以嵌入 XML 文档内部,或作为外部文件引用,主要有三种引入方式:
(1)内部 DTD
DTD 规则直接定义在 XML 文档内部,仅对当前文档有效。
语法格式:
1 |
|
示例:
1 |
|
(2)外部 DTD
DTD 规则存储在独立的.dtd
文件中,可被多个 XML 文档共享,便于维护。
语法格式:
1 |
|
示例:
- note.dtd(外部 DTD 文件):
1 | <!ELEMENT note (to, from, body)> |
XML 文档引用:
1
2
3
4
5
6
7
<note>
<to>ll</to>
<from>zh</from>
<body>hello</body>
</note>
(3)公用 DTD
由权威机构制定的公共 DTD(如 HTML、SVG 的标准 DTD),通过PUBLIC
关键字引入,需指定唯一标识名。
语法格式:
1 |
示例(HTML5 的 DTD):
1 |
DTD 的核心语法
(1)元素声明
定义 XML 元素的结构,包括子元素、文本内容等。
基本语法:
1 | <!ELEMENT 元素名称 元素类型描述> |
元素类型描述:
PCDATA:元素只能包含文本(Parsed Character Data),不能有子元素。
1
<!ELEMENT name (#PCDATA)> <!-- name元素只能是文本 -->
子元素模型:通过符号定义子元素的组成和顺序:
,
:子元素必须按顺序出现(如(a, b, c)
)。
|
:子元素任选其一(如(a | b | c)
)。?
:元素可出现 0 次或 1 次(如a?
)。*
:元素可出现 0 次或多次(如a*
)。+
:元素可出现 1 次或多次(如a+
)。
示例:
1
2<!-- 简历必须包含名字、性别、年龄;电话/手机选一个;家庭住址可选;兴趣爱好可多个;教育经历至少一个 -->
<!ELEMENT 简历 (名字, 性别, 年龄, (电话 | 手机), 家庭住址?, 兴趣爱好*, 教育经历+)>
- EMPTY:元素必须是空元素(无内容)。
1 | <!ELEMENT br EMPTY> <!-- <br/> 是合法的,<br>内容</br> 不合法 --> |
ANY:元素可包含任意内容(文本或子元素)。
1
<!ELEMENT note ANY> <!-- note元素内容无限制 -->
(2)属性声明
定义元素的属性规则,包括属性名、类型、约束和默认值。
基本语法:
1 | <!ATTLIST 元素名 |
属性约束类型:
#REQUIRED
:属性必须存在,无默认值。#IMPLIED
:属性可选,无默认值。#FIXED
:属性值固定为默认值,不可修改。- 直接指定默认值:属性可选,未指定时使用默认值。
常用属性类型:
CDATA
:属性值为字符串。(枚举值1 | 枚举值2 | …):属性值只能是枚举中的一个。
1
<!ATTLIST file type (txt | csv | json) #REQUIRED> <!-- type属性只能是txt、csv或json -->
ID
:属性值为唯一标识符(整个文档中不可重复)。IDREF
:属性值引用另一个元素的ID
属性。
示例:
1 |
|
DTD 的优缺点
优点:
- 语法简单,易于学习和编写。
解析速度快,兼容性好(所有 XML 解析器都支持)。
缺点:
- 不支持数据类型(如整数、日期),只能通过字符串间接约束。
- 不支持命名空间(难以处理多个 DTD 的冲突)。
- 扩展性差,复杂结构约束能力有限。
XML Schema(XML 模式)
XML Schema(简称 XSD)是 W3C 推出的新一代 XML 约束标准,解决了 DTD 的诸多缺陷。它本身是 XML 文档,支持数据类型、命名空间和复杂约束,功能更强大。
XML Schema 的基本结构
示例(定义 note 元素的 Schema):
1 |
|
XML Schema 的核心语法
(1)命名空间与引用
XML Schema 通过命名空间(Namespace)避免元素名冲突,XML 文档需声明引用的 Schema。
XML 文档引用 Schema 的示例:
1 |
|
(2)数据类型
XML Schema 提供了丰富的数据类型,分为简单类型(无子元素和属性)和复杂类型(可包含子元素或属性)。
简单类型
内建类型:直接使用的预定义类型,如:
- 字符串:
xs:string
、xs:normalizedString
(替换换行 / 制表符为空格)。 - 数值:
xs:integer
、xs:decimal
、xs:float
。 - 日期时间:
xs:date
(如2023-10-01
)、xs:dateTime
(如2023-10-01T12:00:00
)。 - 布尔值:
xs:boolean
(true
或false
)。
- 字符串:
自定义简单类型:通过限制、列表或联合内建类型派生。
示例 1:限制类型(年龄必须在 0-120 之间)
1
2
3
4
5
6
7
8<xs:simpleType name="ageType">
<xs:restriction base="xs:integer"> <!-- 基于整数类型限制 -->
<xs:minInclusive value="0"/> <!-- 最小值0 -->
<xs:maxInclusive value="120"/> <!-- 最大值120 -->
</xs:restriction>
</xs:simpleType>
<!-- 使用自定义类型 -->
<xs:element name="age" type="ageType"/>
示例 2:列表类型(多个年龄值)
1 | <xs:simpleType name="ageListType"> |
示例 3:联合类型(价格或日期)
1 | <xs:simpleType name="priceOrDateType"> |
复杂类型
用于定义包含子元素或属性的元素,通过<xs:complexType>
声明。
示例:带属性的复杂类型
1 | <xs:element name="book"> |
合法的 XML 元素:
1 | <book id="1001"> |
XML Schema 的优缺点
优点:
- 支持丰富的数据类型(整数、日期等),约束更精确。
支持命名空间,可组合多个 Schema 文件。
- 本身是 XML 文档,易于解析和扩展。
- 支持复杂结构约束(如条件判断、嵌套类型)。
缺点:
- 语法较复杂,学习成本高。
- 解析速度较 DTD 慢(因功能更强大)。
DTD 与 XML Schema 的对比
特性 | DTD | XML Schema |
---|---|---|
语法 | 非 XML 格式,自有语法 | 纯 XML 格式,遵循 XML 语法 |
数据类型 | 仅支持字符串等简单类型 | 支持丰富的内建类型和自定义类型 |
命名空间支持 | 不支持 | 支持,可避免命名冲突 |
扩展性 | 差 | 好,支持类型派生和组合 |
约束能力 | 基础结构约束 | 复杂结构、数据范围、条件约束等 |
学习曲线 | 简单 | 较复杂 |
兼容性 | 所有 XML 解析器支持 | 需支持 Schema 的解析器 |
选择建议:
- 简单场景(如小型配置文件):使用 DTD,简洁高效。
- 复杂场景(如数据交换、强类型约束):使用 XML Schema,功能更全面。
v1.3.10