DTD 属性声明
本章定位 :掌握 DTD 中
<!ATTLIST>声明的完整语法——属性类型(CDATA/ID/IDREF/NMTOKEN/枚举)、默认值修饰符(#REQUIRED/#IMPLIED/#FIXED)以及 ID/IDREF 的跨元素关联机制。
定义与作用
DTD 中的 <!ATTLIST> 声明用于定义元素可以携带哪些属性、每个属性的类型、是否必填、以及默认值。
DTD 属性声明的两个核心功能:
- 约束属性的值类型 :如 ID(全局唯一标识)、枚举(限定可选值)、IDREF(引用其他元素的 ID)
- 控制属性的存在性 :#REQUIRED(必填)、#IMPLIED(可选)、#FIXED(固定值)
核心原理:ID/IDREF 关联机制
图解释 :ID/IDREF 机制在 XML 文档内部建立类似"外键"的关系。enrollment 通过 student_ref 和 course_ref 属性引用 student 和 course 的 ID——验证器会检查引用的 ID 是否存在。
语法/结构要点
属性类型一览
| 类型 | 说明 | 示例 |
|---|---|---|
| CDATA | 任意字符串(最常用) | name CDATA #REQUIRED |
| ID | 全局唯一标识符 | id ID #REQUIRED |
| IDREF | 引用另一个元素的 ID | student_ref IDREF #REQUIRED |
| IDREFS | 引用多个 ID(空格分隔) | refs IDREFS #IMPLIED |
| NMTOKEN | 单个有效名称标记 | country NMTOKEN #REQUIRED |
| 枚举 | 从指定列表中选一 | gender (male|female) #REQUIRED |
默认值修饰符
| 修饰符 | 含义 | XML 中可以省略吗? |
|---|---|---|
#REQUIRED | 必填 | 否 |
#IMPLIED | 可选,无默认值 | 可以 |
#FIXED "value" | 固定值,不能改 | 可以(自动取固定值) |
"default" | 有默认值 | 可以(不写则取默认值) |
完整示例:黄俪设计选课系统的 DTD
场景说明
飞翔科技的测试工程师 黄俪 负责验证学生选课系统的 XML 数据。她设计了一套 DTD,利用 ID/IDREF 确保"学生选课"数据的一致性——每个选课记录引用的学生和课程 ID 都必须存在。
操作前:无约束的 XML
<?xml version="1.0" encoding="UTF-8"?>
<university>
<student id="S001" name="小崔"/>
<student id="S002" name="黄俪"/>
<course id="CS301" name="XML技术"/>
<course id="CS402" name="Java高级"/>
<!-- 引用了不存在的 student id="S999" -->
<enrollment student_id="S999" course_id="CS301"/>
</university>
操作后:DTD 属性声明 + ID/IDREF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE university [
<!ELEMENT university (student*, course*, enrollment*)>
<!ELEMENT student EMPTY>
<!ATTLIST student
id ID #REQUIRED
name CDATA #REQUIRED
major CDATA #IMPLIED
status (active|graduated|suspended) "active">
<!ELEMENT course EMPTY>
<!ATTLIST course
id ID #REQUIRED
name CDATA #REQUIRED
credits CDATA #REQUIRED
semester (spring|fall|summer) #REQUIRED>
<!ELEMENT enrollment EMPTY>
<!ATTLIST enrollment
student_ref IDREF #REQUIRED
course_ref IDREF #REQUIRED
grade CDATA #IMPLIED>
]>
<university>
<student id="S001" name="小崔" major="计算机科学"/>
<student id="S002" name="黄俪" major="软件工程" status="active"/>
<course id="CS301" name="XML技术" credits="3" semester="fall"/>
<course id="CS402" name="Java高级" credits="4" semester="spring"/>
<enrollment student_ref="S001" course_ref="CS301" grade="A"/>
<enrollment student_ref="S002" course_ref="CS301"/>
<enrollment student_ref="S002" course_ref="CS402" grade="B+"/>
</university>
操作结果
DTD 验证器在解析过程中会执行以下检查:
- 每个
student/@id和course/@id全局唯一(ID 类型保证) - 每个
enrollment/@student_ref引用的 ID 必须存在于文档中的student/@id(IDREF 检查) status只能取active、graduated、suspended之一,省略时默认为activesemester只能取spring、fall、summer之一
黄俪测试时发现:如果 XML 中有 student_ref="S999",DTD 验证会直接报错——"引用的 ID 不存在"。
易错场景
错误一:ID 值以数字开头
<!-- ❌ ID 类型要求值是合法的 XML 名称(不能以数字开头) -->
<student id="001" name="小崔"/>
<!-- ✅ 加前缀 -->
<student id="S001" name="小崔"/>
错误二:混淆 #IMPLIED 和 #FIXED
<!ATTLIST element attr1 CDATA #IMPLIED> <!-- 可选,无默认值 -->
<!ATTLIST element attr2 CDATA #FIXED "x"> <!-- 固定为 "x",写别的值就报错 -->
错误三:枚举值没有引号
DTD 属性声明中,枚举值和默认值都不需要引号,这与 XML 文档中属性值必须加引号不同。
<!-- ✅ DTD 声明中 -->
<!ATTLIST course semester (spring | fall) #REQUIRED>
<!-- ✅ XML 文档中 -->
<course semester="spring"/>
面试考点
| 考点 | 参考答案要点 |
|---|---|
| DTD 中 #REQUIRED、#IMPLIED、#FIXED 的区别? | #REQUIRED 必填;#IMPLIED 可选且无默认值;#FIXED 固定值,不能在 XML 中修改 |
| ID 和 IDREF 如何实现数据完整性? | ID 保证元素有全局唯一标识符;IDREF 引用其他元素的 ID,验证器会检查引用目标是否存在——类似数据库外键 |
| CDATA 属性类型在 DTD 和 XML 中分别是什么含义? | 在 DTD 中 CDATA 是属性类型(表示字符数据);在 XML 中 CDATA 是转义块(<![CDATA[...]]>)。同名不同义 |