如何在XSD中定义含二选一必填元素的无序列表?
XSD实现任意排序元素+二选一约束的解决方案
方案一:XSD 1.1(推荐,简洁直接)
XSD 1.1支持的断言(xs:assert)是解决这个需求的最优解,既能让元素任意排序,又能精准约束Element3a和Element3b的二选一规则。
示例代码:
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" vc:minVersion="1.1"> <xs:element name="RootElement"> <xs:complexType> <xs:all> <!-- 必填元素 --> <xs:element name="Element1" type="xs:string" minOccurs="1" maxOccurs="1"/> <xs:element name="Element2" type="xs:int" minOccurs="1" maxOccurs="1"/> <!-- 可选元素 --> <xs:element name="Element4" type="xs:date" minOccurs="0" maxOccurs="1"/> <xs:element name="Element5" type="xs:boolean" minOccurs="0" maxOccurs="1"/> <!-- 先把二选一元素设为可选,再用断言约束出现规则 --> <xs:element name="Element3a" type="xs:string" minOccurs="0" maxOccurs="1"/> <xs:element name="Element3b" type="xs:int" minOccurs="0" maxOccurs="1"/> </xs:all> <!-- 断言逻辑:两个元素的出现次数之和必须等于1 --> <xs:assert test="count(Element3a) + count(Element3b) = 1"/> </xs:complexType> </xs:element> </xs:schema>
关键说明:
xs:all天然支持内部元素任意顺序排列,且每个元素最多出现一次,完全匹配你的maxOccurs=1要求xs:assert里的XPath表达式直接卡死了Element3a和Element3b的出现规则:必须恰好出现一个,不能同时存在也不能都不出现- 一定要在schema开头声明
vc:minVersion="1.1",否则断言不会生效,现在主流的XML解析器都支持XSD 1.1,兼容性问题不大
方案二:XSD 1.0(兼容老版本解析器)
如果必须适配仅支持XSD 1.0的老工具,就得用分组+约束的方式绕路实现,因为XSD 1.0不支持断言,且xs:all里不能嵌套xs:choice。
示例代码:
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <!-- 定义必填元素组 --> <xs:group name="RequiredElements"> <xs:sequence> <xs:element name="Element1" type="xs:string"/> <xs:element name="Element2" type="xs:int"/> </xs:sequence> </xs:group> <!-- 定义可选元素组 --> <xs:group name="OptionalElements"> <xs:sequence> <xs:element name="Element4" type="xs:date" minOccurs="0"/> <xs:element name="Element5" type="xs:boolean" minOccurs="0"/> </xs:sequence> </xs:group> <!-- 定义二选一元素组 --> <xs:group name="ExclusiveElements"> <xs:choice> <xs:element name="Element3a" type="xs:string"/> <xs:element name="Element3b" type="xs:int"/> </xs:choice> </xs:group> <xs:element name="RootElement"> <xs:complexType> <xs:choice maxOccurs="unbounded"> <xs:group ref="RequiredElements"/> <xs:group ref="OptionalElements"/> <xs:group ref="ExclusiveElements"/> </xs:choice> <!-- 约束必填元素仅出现一次 --> <xs:unique name="UniqueElement1"> <xs:selector xpath="Element1"/> <xs:field xpath="."/> </xs:unique> <xs:unique name="UniqueElement2"> <xs:selector xpath="Element2"/> <xs:field xpath="."/> </xs:unique> <!-- 约束二选一元素不能同时出现 --> <xs:unique name="UniqueExclusive"> <xs:selector xpath="Element3a | Element3b"/> <xs:field xpath="name()"/> </xs:unique> <!-- 约束必填元素必须出现 --> <xs:key name="MustHaveElement1"> <xs:selector xpath="Element1"/> <xs:field xpath="."/> </xs:key> <xs:key name="MustHaveElement2"> <xs:selector xpath="Element2"/> <xs:field xpath="."/> </xs:key> </xs:complexType> </xs:element> </xs:schema>
关键说明:
- 通过
xs:choice maxOccurs="unbounded"让各组可以任意顺序排列,但需要额外的约束来避免元素重复或缺失 xs:key确保必填元素必须出现,xs:unique确保每个元素只出现一次、二选一元素不会同时存在- 这种写法配置繁琐,且部分老解析器对复杂的唯一性约束支持有限,能不用就不用
内容的提问来源于stack exchange,提问作者Andreas
相关产品推荐
相关产品推荐

