验证xml格式
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 文档内部,仅对当前文档有效。
语法格式:
<!-- XML文档内容 -->
示例:
<note>
<to>ll</to>
<from>zh</from>
<body>hello</body>
</note>
(2)外部 DTD
DTD 规则存储在独立的.dtd文件中,可被多个 XML 文档共享,便于维护。
语法格式:
<!-- XML文档内容 -->
示例:
- note.dtd(外部 DTD 文件):
<!ELEMENT note (to, from, body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT body (#PCDATA)>
XML 文档引用:
<note> <to>ll</to> <from>zh</from> <body>hello</body> </note>
(3)公用 DTD
由权威机构制定的公共 DTD(如 HTML、SVG 的标准 DTD),通过PUBLIC关键字引入,需指定唯一标识名。
语法格式:
示例(HTML5 的 DTD):
DTD 的核心语法
(1)元素声明
定义 XML 元素的结构,包括子元素、文本内容等。
基本语法:
<!ELEMENT 元素名称 元素类型描述>
元素类型描述:
PCDATA:元素只能包含文本(Parsed Character Data),不能有子元素。
<!ELEMENT name (#PCDATA)> <!-- name元素只能是文本 -->子元素模型:通过符号定义子元素的组成和顺序:
,:子元素必须按顺序出现(如(a, b, c))。
|:子元素任选其一(如(a | b | c))。?:元素可出现 0 次或 1 次(如a?)。*:元素可出现 0 次或多次(如a*)。+:元素可出现 1 次或多次(如a+)。
示例:
<!-- 简历必须包含名字、性别、年龄;电话/手机选一个;家庭住址可选;兴趣爱好可多个;教育经历至少一个 --> <!ELEMENT 简历 (名字, 性别, 年龄, (电话 | 手机), 家庭住址?, 兴趣爱好*, 教育经历+)>
- EMPTY:元素必须是空元素(无内容)。
<!ELEMENT br EMPTY> <!-- <br/> 是合法的,<br>内容</br> 不合法 -->
ANY:元素可包含任意内容(文本或子元素)。
<!ELEMENT note ANY> <!-- note元素内容无限制 -->
(2)属性声明
定义元素的属性规则,包括属性名、类型、约束和默认值。
基本语法:
<!ATTLIST 元素名
属性名1 属性类型1 约束1 [默认值1]
属性名2 属性类型2 约束2 [默认值2]
>
属性约束类型:
#REQUIRED:属性必须存在,无默认值。#IMPLIED:属性可选,无默认值。#FIXED:属性值固定为默认值,不可修改。- 直接指定默认值:属性可选,未指定时使用默认值。
常用属性类型:
CDATA:属性值为字符串。(枚举值1 | 枚举值2 | …):属性值只能是枚举中的一个。
<!ATTLIST file type (txt | csv | json) #REQUIRED> <!-- type属性只能是txt、csv或json -->ID:属性值为唯一标识符(整个文档中不可重复)。IDREF:属性值引用另一个元素的ID属性。
示例:
<email from="zh" to="ll">
<body>hello</body>
</email>
DTD 的优缺点
优点:
- 语法简单,易于学习和编写。
解析速度快,兼容性好(所有 XML 解析器都支持)。
缺点:
- 不支持数据类型(如整数、日期),只能通过字符串间接约束。
- 不支持命名空间(难以处理多个 DTD 的冲突)。
- 扩展性差,复杂结构约束能力有限。
XML Schema(XML 模式)
XML Schema(简称 XSD)是 W3C 推出的新一代 XML 约束标准,解决了 DTD 的诸多缺陷。它本身是 XML 文档,支持数据类型、命名空间和复杂约束,功能更强大。
XML Schema 的基本结构
示例(定义 note 元素的 Schema):
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema" <!-- 引入Schema命名空间,前缀xs -->
targetNamespace="http://example.com/note" <!-- 当前Schema的命名空间 -->
xmlns="http://example.com/note" <!-- 默认命名空间 -->
elementFormDefault="qualified"> <!-- 元素必须用命名空间限定 -->
<!-- 定义note元素,类型为复杂类型(包含子元素) -->
<xs:element name="note">
<xs:complexType>
<xs:sequence> <!-- 子元素按顺序出现 -->
<xs:element name="to" type="xs:string"/> <!-- to元素为字符串类型 -->
<xs:element name="from" type="xs:string"/> <!-- from元素为字符串类型 -->
<xs:element name="body" type="xs:string"/> <!-- body元素为字符串类型 -->
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
XML Schema 的核心语法
(1)命名空间与引用
XML Schema 通过命名空间(Namespace)避免元素名冲突,XML 文档需声明引用的 Schema。
XML 文档引用 Schema 的示例:
<note
xmlns="http://example.com/note" <!-- 默认命名空间,与Schema的targetNamespace一致 -->
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <!-- Schema实例命名空间 -->
xsi:schemaLocation="http://example.com/note note.xsd"> <!-- 绑定命名空间与Schema文件 -->
<to>ll</to>
<from>zh</from>
<body>hello</body>
</note>
(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 之间)
<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:列表类型(多个年龄值)
<xs:simpleType name="ageListType">
<xs:list itemType="ageType"/> <!-- 基于ageType的列表 -->
</xs:simpleType>
<xs:element name="ages" type="ageListType"/> <!-- 合法值:"18 25 30" -->
示例 3:联合类型(价格或日期)
<xs:simpleType name="priceOrDateType">
<xs:union memberTypes="xs:decimal xs:date"/> <!-- 可接受小数或日期 -->
</xs:simpleType>
<xs:element name="value" type="priceOrDateType"/> <!-- 合法值:"99.9" 或 "2023-10-01" -->
复杂类型
用于定义包含子元素或属性的元素,通过<xs:complexType>声明。
示例:带属性的复杂类型
<xs:element name="book">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="author" type="xs:string"/>
</xs:sequence>
<!-- 定义属性 -->
<xs:attribute name="id" type="xs:integer" use="required"/> <!-- 必需属性id -->
<xs:attribute name="category" type="xs:string" default="fiction"/> <!-- 可选属性,默认fiction -->
</xs:complexType>
</xs:element>
合法的 XML 元素:
<book id="1001">
<title>XML Guide</title>
<author>John</author>
</book>
XML Schema 的优缺点
优点:
- 支持丰富的数据类型(整数、日期等),约束更精确。
支持命名空间,可组合多个 Schema 文件。
- 本身是 XML 文档,易于解析和扩展。
- 支持复杂结构约束(如条件判断、嵌套类型)。
缺点:
- 语法较复杂,学习成本高。
- 解析速度较 DTD 慢(因功能更强大)。
DTD 与 XML Schema 的对比
| 特性 | DTD | XML Schema |
|---|---|---|
| 语法 | 非 XML 格式,自有语法 | 纯 XML 格式,遵循 XML 语法 |
| 数据类型 | 仅支持字符串等简单类型 | 支持丰富的内建类型和自定义类型 |
| 命名空间支持 | 不支持 | 支持,可避免命名冲突 |
| 扩展性 | 差 | 好,支持类型派生和组合 |
| 约束能力 | 基础结构约束 | 复杂结构、数据范围、条件约束等 |
| 学习曲线 | 简单 | 较复杂 |
| 兼容性 | 所有 XML 解析器支持 | 需支持 Schema 的解析器 |
选择建议:
- 简单场景(如小型配置文件):使用 DTD,简洁高效。
- 复杂场景(如数据交换、强类型约束):使用 XML Schema,功能更全面。