XSD条件约束子元素存在性时类型派生报错解决
错误根因
报错来自XSD类型派生的硬性规则限制:
- 用
<xs:simpleContent>定义的复杂类型,内容模型固定为「纯文本+属性、不允许子元素」,即使手动加mixed="true"也不会改变这个判定。这类类型不能被使用<xs:complexContent>的类型继承扩展,这就是你看到「派生类型与基类型内容模型不匹配,一个mixed一个非mixed」错误的核心原因。 - 你一开始用
<xs:alternative>做条件类型分支的思路完全可行,问题出在基类型和派生类型跨了simpleContent/complexContent两种内容模型,违反了XSD的派生规则。
修正方案
不需要做跨内容模型的类型扩展,直接把两个条件分支的类型统一定义为mixed="true"的complexContent类型,仅在until="random"对应的分支里加入random子元素的定义,从根源避开继承规则限制。
修正后的可运行XSD代码如下:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <!-- 原有枚举类型定义完全保留 --> <xs:simpleType name="type2"> <xs:restriction base="xs:string"> <xs:enumeration value="Dice Roll"/> <xs:enumeration value="Wait"/> <xs:enumeration value="Repeat"/> <xs:enumeration value="Double Roll"/> <xs:enumeration value="Instruction"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="until"> <xs:restriction base="xs:string"> <xs:enumeration value="end"/> <xs:enumeration value="random"/> <xs:enumeration value="Instruction"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="annotation"> <xs:restriction base="xs:string"> <xs:enumeration value="rolltwice"/> <xs:enumeration value="halfcount"/> <xs:enumeration value="doublecount"/> <xs:enumeration value="roll-"/> <xs:enumeration value="roll+"/> <xs:enumeration value="numberChange"/> <xs:enumeration value="NoNumberChange"/> </xs:restriction> </xs:simpleType> <xs:simpleType name="extended"> <xs:restriction base="xs:string"> <xs:enumeration value="noRolling"/> <xs:enumeration value="noEven"/> <xs:enumeration value="noUneven"/> <xs:enumeration value="stopped"/> </xs:restriction> </xs:simpleType> <!-- random子元素类型保留原有属性和断言 --> <xs:complexType name="random"> <xs:attribute name="start" type="xs:integer"/> <xs:attribute name="end" type="xs:integer"/> <xs:assert test="@start le @end"/> </xs:complexType> <!-- 非random分支:仅允许文本+属性,禁止random子元素 --> <xs:complexType name="simpleTypeContent" mixed="true"> <xs:complexContent> <xs:restriction base="xs:anyType"> <xs:sequence> <!-- 不声明random元素,禁止该子元素出现 --> </xs:sequence> <xs:attribute name="until"> <xs:simpleType> <xs:union memberTypes="type2 annotation xs:integer until"/> </xs:simpleType> </xs:attribute> <xs:attribute name="condition"> <xs:simpleType> <xs:union memberTypes="type2 annotation extended"/> </xs:simpleType> </xs:attribute> <xs:attribute name="repeat" type="xs:integer"/> <!-- 校验文本内容符合type2枚举要求 --> <xs:assert test="normalize-space(.) instance of element(*, type2)"/> </xs:restriction> </xs:complexContent> </xs:complexType> <!-- random分支:允许random子元素+文本+属性 --> <xs:complexType name="complexTypeContent" mixed="true"> <xs:complexContent> <xs:restriction base="xs:anyType"> <xs:sequence> <xs:element name="random" type="random" minOccurs="0" maxOccurs="1"/> </xs:sequence> <xs:attribute name="until" use="required" fixed="random"/> <xs:attribute name="condition"> <xs:simpleType> <xs:union memberTypes="type2 annotation extended"/> </xs:simpleType> </xs:attribute> <xs:attribute name="repeat" type="xs:integer"/> <xs:assert test="normalize-space(.) instance of element(*, type2)"/> </xs:restriction> </xs:complexContent> </xs:complexType> <!-- 根结构保留原有条件类型判断逻辑 --> <xs:element name="root"> <xs:complexType> <xs:sequence maxOccurs="unbounded"> <xs:element name="instruction" maxOccurs="unbounded" minOccurs="0"> <xs:complexType> <xs:sequence> <xs:element name="type"> <xs:alternative test="@until = 'random'" type="complexTypeContent"/> <xs:alternative type="simpleTypeContent"/> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>
校验效果说明
- 给出的合法样例(
until='random'且包含random子元素)可以正常通过校验 - 给出的非法样例(
until='2'且包含random子元素)会被直接判定为不符合schema规则 - 原有所有属性的枚举约束、
start <= end的断言、文本内容的枚举限制都完整保留,兼容之前的业务规则。
内容的提问来源于stack exchange,提问作者Daniel Janz
相关产品推荐
相关产品推荐

