XSD的xs:key和xs:keyref是XML Schema中用于定义唯一性约束和引用约束的核心元素,二者配合可以模拟关系型数据库的主键和外键机制,确保XML实例数据中的元素值满足唯一性和引用有效性的要求。
xs:key和xs:keyref的基本概念
xs:key用于在指定的作用域内定义一个唯一性约束,相当于关系型数据库中的主键,要求被约束的元素或属性值在作用域内必须唯一,且不能为空。xs:keyref则用于定义引用约束,相当于外键,它的值必须匹配某个已定义的xs:key的约束值,确保引用的有效性。
xs:key的配置结构
xs:key需要包含三个核心部分:name属性用于标识约束名称,selector通过XPath指定约束的作用范围,field通过XPath指定需要唯一的值所在的节点或属性。示例配置如下:
<xs:key name="studentIdKey"> <xs:selector xpath="./student"/> <xs:field xpath="@id"/> </xs:key>
上述配置表示在当前的父节点下,所有<student>元素的id属性值必须唯一,构成student元素的主键约束。
xs:keyref的配置结构
xs:keyref需要包含refer属性,指向要引用的xs:key的name,同时selector指定外键所在的元素范围,field指定外键值的节点或属性。示例配置如下:
<xs:keyref name="scoreStudentRef" refer="studentIdKey"> <xs:selector xpath="./score"/> <xs:field xpath="@studentId"/> </xs:keyref>
上述配置表示所有<score>元素的studentId属性值,必须存在于studentIdKey约束定义的id值中,形成外键引用关系。
完整实现示例
下面通过一个学生成绩管理的XML场景,演示完整的XSD约束定义和对应的XML实例。
XSD约束文件
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- 定义根元素 -->
<xs:element name="school">
<xs:complexType>
<xs:sequence>
<xs:element name="student" type="studentType" maxOccurs="unbounded"/>
<xs:element name="score" type="scoreType" maxOccurs="unbounded"/>
</xs:sequence>
<!-- 定义student的id为主键 -->
<xs:key name="studentIdKey">
<xs:selector xpath="./student"/>
<xs:field xpath="@id"/>
</xs:key>
<!-- 定义score的studentId为外键,引用studentIdKey -->
<xs:keyref name="scoreStudentRef" refer="studentIdKey">
<xs:selector xpath="./score"/>
<xs:field xpath="@studentId"/>
</xs:keyref>
</xs:complexType>
</xs:element>
<!-- 学生元素类型 -->
<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="scoreType">
<xs:attribute name="studentId" type="xs:string" use="required"/>
<xs:attribute name="course" type="xs:string" use="required"/>
<xs:attribute name="value" type="xs:integer" use="required"/>
</xs:complexType>
</xs:schema>
符合约束的XML实例
<?xml version="1.0" encoding="UTF-8"?>
<school xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="school.xsd">
<student id="S001" name="张三"/>
<student id="S002" name="李四"/>
<score studentId="S001" course="数学" value="90"/>
<score studentId="S002" course="数学" value="85"/>
</school>
上述XML中,两个学生的id分别是S001和S002,成绩中的studentId都对应存在的id值,因此校验会通过。
违反约束的XML实例
如果将某个成绩的studentId改为S003,由于S003不在studentIdKey的约束值中,校验时会提示外键引用错误。如果存在两个student的id都是S001,会提示主键重复错误。
常见注意事项
- selector和field中的XPath表达式需要基于xs:key或xs:keyref所在的父节点进行定位,避免路径错误导致约束不生效。
- xs:key约束的字段不能为空,而xs:keyref的字段如果允许为空,需要额外配置nillable属性,否则空值会校验失败。
- 如果XML实例使用了命名空间,XPath表达式中需要正确声明命名空间前缀,否则无法匹配到对应的节点。
- xs:key和xs:keyref的作用域是定义它们的父元素及其所有子元素,不同作用域下的同名约束不会互相影响。
校验方法
可以通过各类XML编辑工具或者编程语言的XML解析库进行约束校验,以下是Java中使用DOM解析器校验的示例代码:
import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.File;
public class XsdValidator {
public static void main(String[] args) {
try {
// 创建Schema工厂
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
// 加载XSD文件
Schema schema = factory.newSchema(new File("school.xsd"));
// 创建校验器
Validator validator = schema.newValidator();
// 校验XML文件
validator.validate(new StreamSource(new File("school.xml")));
System.out.println("XML校验通过");
} catch (Exception e) {
System.out.println("XML校验失败:" + e.getMessage());
}
}
}
运行上述代码后,如果XML实例符合XSD中xs:key和xs:keyref的约束,会输出校验通过,否则会抛出异常提示具体的约束违反信息。