XML Schema中的key和keyref是专门用于实现XML文档内部数据完整性约束的核心组件,二者配合可以模拟关系型数据库的主键和外键机制,确保XML数据在标识唯一性和引用有效性上符合预设规则。

key和keyref的基本概念
key的作用是在XML文档的某个作用域内定义一个唯一标识约束,被标记为key的节点值在该作用域内必须唯一,不允许出现重复值,功能类似关系型数据库的主键。key的定义需要指定作用范围、目标节点以及用于唯一标识的字段。
keyref的作用是建立两个节点之间的引用关系,它的值必须匹配某个已定义的key的值,功能类似关系型数据库的外键。keyref需要指定自身的作用范围、目标节点、引用字段,以及要引用的key的名称。
XML Schema中定义key和keyref的语法
key和keyref都需要定义在xs:element或者xs:complexType内部,核心子元素包含以下三类:
xs:selector:用于指定约束的作用范围,通过XPath表达式匹配需要应用约束的节点集合xs:field:用于指定作为唯一标识或者引用值的字段,同样通过XPath表达式匹配节点的值- keyref额外需要
refer属性,用于指定要引用的key的限定名
完整实现示例
下面通过一个学生选课的场景来演示如何实现完整性约束,场景包含学生信息和课程信息,选课记录中的课程编号必须存在于课程列表的编号中。
1. 定义XML Schema文件
首先编写包含key和keyref定义的Schema文件,定义课程编号的key,以及选课记录中课程编号的keyref:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://example.org/student"
xmlns:tns="http://example.org/student"
elementFormDefault="qualified">
<!-- 定义根元素 -->
<xs:element name="studentSystem" type="tns:studentSystemType"/>
<xs:complexType name="studentSystemType">
<xs:sequence>
<xs:element name="courses" type="tns:coursesType"/>
<xs:element name="students" type="tns:studentsType"/>
<xs:element name="enrollments" type="tns:enrollmentsType"/>
<xs:sequence>
<!-- 定义课程编号的key约束,作用在整个courses节点下的所有course节点 -->
<xs:key name="courseIdKey">
<xs:selector xpath="tns:courses/tns:course"/>
<xs:field xpath="@id"/>
</xs:key>
<!-- 定义选课记录中课程编号的keyref约束,引用上面的courseIdKey -->
<xs:keyref name="enrollmentCourseRef" refer="tns:courseIdKey">
<xs:selector xpath="tns:enrollments/tns:enrollment"/>
<xs:field xpath="tns:courseId"/>
</xs:keyref>
</xs:complexType>
<!-- 课程列表类型定义 -->
<xs:complexType name="coursesType">
<xs:sequence>
<xs:element name="course" type="tns:courseType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="courseType">
<xs:attribute name="id" type="xs:string" use="required"/>
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
<!-- 学生列表类型定义 -->
<xs:complexType name="studentsType">
<xs:sequence>
<xs:element name="student" type="tns:studentType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="studentType">
<xs:attribute name="id" type="xs:string" use="required"/>
<xs:attribute name="name" type="xs:string" use="required"/>
</xs:complexType>
<!-- 选课记录列表类型定义 -->
<xs:complexType name="enrollmentsType">
<xs:sequence>
<xs:element name="enrollment" type="tns:enrollmentType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="enrollmentType">
<xs:sequence>
<xs:element name="studentId" type="xs:string"/>
<xs:element name="courseId" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
2. 符合约束的XML示例
以下XML文档符合上面Schema定义的完整性约束,选课记录中的课程编号都存在于课程列表中:
<?xml version="1.0" encoding="UTF-8"?>
<studentSystem xmlns="http://example.org/student"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://example.org/student student.xsd">
<courses>
<course id="C001" name="数据结构"/>
<course id="C002" name="操作系统"/>
<course id="C003" name="计算机网络"/>
</courses>
<students>
<student id="S001" name="张三"/>
<student id="S002" name="李四"/>
</students>
<enrollments>
<enrollment>
<studentId>S001</studentId>
<courseId>C001</courseId>
</enrollment>
<enrollment>
<studentId>S001</studentId>
<courseId>C002</courseId>
</enrollment>
<enrollment>
<studentId>S002</studentId>
<courseId>C003</courseId>
</enrollment>
</enrollments>
</studentSystem>
3. 违反约束的XML示例
如果选课记录中出现不存在的课程编号,比如courseId为C004,XML校验器会报错,提示keyref约束失败:
<?xml version="1.0" encoding="UTF-8"?>
<studentSystem xmlns="http://example.org/student"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://example.org/student student.xsd">
<courses>
<course id="C001" name="数据结构"/>
<course id="C002" name="操作系统"/>
</courses>
<students>
<student id="S001" name="张三"/>
</students>
<enrollments>
<enrollment>
<studentId>S001</studentId>
<courseId>C003</courseId> <!-- 该编号不存在于课程列表中,违反keyref约束 -->
</enrollment>
</enrollments>
</studentSystem>
注意事项
- key和keyref的
xs:selector和xs:field中的XPath表达式需要符合XML Schema的XPath子集规范,不支持完整的XPath 1.0语法 - 如果key定义在某个复杂类型中,那么该key的作用域仅限于该类型对应的元素及其子元素
- key约束的字段值不能为空,空值不会被判定为唯一值,而keyref的字段值如果为空则不会触发引用校验
- 同一个XML Schema中可以定义多个key和keyref,分别用于不同场景的完整性约束
XML_Schemakeykeyref完整性约束修改时间:2026-07-22 12:27:42