如何在XSD中限定元素仅能出现在带有指定属性值的父元素内
首先你之前写的那种把<xs:element>放在<xs:attribute>内部的写法不符合XSD语法规范,确实是对XSD用法的认知误区:XSD中属性的声明节点下不能嵌套元素定义,属性和元素的结构约束是分开定义的。
要实现「根据item的name属性值限制允许的子元素」的需求,根据你使用的XSD版本有两种实现方案:
方案1:使用XSD 1.1(最简洁)
XSD 1.1引入了*条件类型分配(Conditional Type Assignment)*特性,刚好匹配你的需求,还支持你提到的「coolThing同时出现在name=foo和name=baz的item下」的扩展场景,写法如下:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" vc:minVersion="1.1" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"> <!-- 定义name=foo的item对应结构 --> <xs:complexType name="itemFooType"> <xs:sequence> <xs:element name="coolThing" type="xs:string"/> </xs:sequence> <xs:attribute name="name" type="xs:string" fixed="foo"/> </xs:complexType> <!-- 定义name=bar的item对应结构 --> <xs:complexType name="itemBarType"> <xs:sequence> <xs:element name="needfulThing" type="xs:string"/> </xs:sequence> <xs:attribute name="name" type="xs:string" fixed="bar"/> </xs:complexType> <!-- 给item节点添加条件类型分配规则 --> <xs:complexType name="itemType"> <xs:alternative test="@name='foo'" type="itemFooType"/> <xs:alternative test="@name='bar'" type="itemBarType"/> <!-- 要支持coolThing同时在name=foo和name=baz下,直接修改test条件即可: <xs:alternative test="@name='foo' or @name='baz'" type="itemFooType"/> --> </xs:complexType> <!-- 根元素定义 --> <xs:element name="items"> <xs:complexType> <xs:sequence> <xs:element name="item" type="itemType" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
方案2:仅能使用XSD 1.0的替代方案
XSD 1.0没有原生支持按属性值分配结构的特性,有两种可选的兼容方案:
- 最优方案:调整XML结构,把不同类型的item改成不同的元素名,比如
<fooItem>、<barItem>,分别定义各自的子元素结构,这也是XSD 1.0下最符合设计规范、兼容性最好的实现方式。 - 兼容方案:XSD中用
<xs:choice>定义所有可能出现的子元素,再补充Schematron规则限制不同name属性下允许出现的子元素,这种方案需要校验工具同时支持XSD和Schematron才能生效。
内容的提问来源于stack exchange,提问作者John McMullen
相关产品推荐
相关产品推荐

