XSD中complexType内定义keyref出现找不到匹配键引用报错问题
问题背景
需要用XSD实现以下元素结构:
- glossary
- definition(term属性值唯一)
- term(ref属性指向某条definition的term属性值)
- definition(term属性值唯一)
具体规则:
- glossary可包含多条definition节点,每个definition的term属性唯一
- definition内部支持混合文本和term元素
keyref(命名为termRef)需要作为textType这个complexType的公共能力,可在XSD多处复用,不止用于definition节点。
现有代码
XSD代码
<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="foo" xmlns="foo" xmlns:xsfoo="foo" elementFormDefault="qualified"> <xs:complexType name="textType" mixed="true"> <xs:choice maxOccurs="unbounded"> <xs:element name="term" minOccurs="0" maxOccurs="unbounded"> <xs:complexType> <xs:simpleContent> <xs:extension base="xs:normalizedString"> <xs:attribute name="ref" use="required" type="xs:token"/> </xs:extension> </xs:simpleContent> </xs:complexType> <xs:keyref name="termRef" refer="glossaryTermUnique"> <xs:selector xpath="."/> <xs:field xpath="@ref"/> </xs:keyref> </xs:element> </xs:choice> </xs:complexType> <xs:element name="foo"> <xs:complexType> <xs:sequence> <xs:element name="glossary"> <xs:complexType> <xs:sequence> <xs:element name="definition" minOccurs="0" maxOccurs="unbounded"> <xs:complexType> <xs:complexContent> <xs:extension base="textType"> <xs:attribute name="term" use="required" type="xs:token"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> <xs:unique name="glossaryTermUnique"> <xs:selector xpath="xsfoo:definition"/> <xs:field xpath="@term"/> </xs:unique> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
测试XML代码
<?xml version="1.0"?> <foo xmlns="foo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="foo test.xsd"> <glossary> <definition term="ik 1">identification key 1</definition> <definition term="ik 2">identification key 2 with <term ref="ik 1">a ik 1 reference</term></definition> </glossary> </foo>
报错信息
Schemas validity error : Element '{foo}term': No match found for key-sequence ['ik 1'] of keyref '{foo}termRef'.
问题原因
核心问题是身份约束(key/keyref/unique)的定义位置不符合XSD规范:
- 身份约束只能作为元素声明(
<xs:element>)的直接子元素,不能定义在全局complexType内部的局部元素声明下,你将termRef写在textType内部的term元素下,本身就是不合法的,导致约束作用域异常。 - 原来的
glossaryTermUnique定义在glossary元素下,作用域仅覆盖glossary子树,和异常的termRef作用域不匹配,无法被引用。
修复方案
既满足textType复用需求,又符合XSD规范的修改如下:
- 删除
textType内部term元素下的keyref定义 - 在根元素
foo的声明下,同时定义unique和keyref约束,覆盖整个文档范围的definition和term节点,不管textType用在哪个位置都能正常校验。
修复后的完整XSD代码:
<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="foo" xmlns="foo" xmlns:xsfoo="foo" elementFormDefault="qualified"> <xs:complexType name="textType" mixed="true"> <xs:choice maxOccurs="unbounded"> <xs:element name="term" minOccurs="0" maxOccurs="unbounded"> <xs:complexType> <xs:simpleContent> <xs:extension base="xs:normalizedString"> <xs:attribute name="ref" use="required" type="xs:token"/> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> <xs:element name="foo"> <xs:complexType> <xs:sequence> <xs:element name="glossary"> <xs:complexType> <xs:sequence> <xs:element name="definition" minOccurs="0" maxOccurs="unbounded"> <xs:complexType> <xs:complexContent> <xs:extension base="textType"> <xs:attribute name="term" use="required" type="xs:token"/> </xs:extension> </xs:complexContent> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> <!-- 全局唯一键,校验所有definition的term属性唯一 --> <xs:unique name="glossaryTermUnique"> <xs:selector xpath="xsfoo:glossary/xsfoo:definition"/> <xs:field xpath="@term"/> </xs:unique> <!-- 全局键引用,校验所有term的ref属性指向存在的term值 --> <xs:keyref name="termRef" refer="glossaryTermUnique"> <xs:selector xpath=".//xsfoo:term"/> <xs:field xpath="@ref"/> </xs:keyref> </xs:element> </xs:schema>
修改后重新校验即可正常通过,同时textType可以任意复用到其他元素下,所有使用textType的元素中的term节点都会自动触发引用校验。
内容的提问来源于stack exchange,提问作者Raphhh
相关产品推荐
相关产品推荐

