答案部分取决于您到底想说什么,部分取决于您使用的模式语言:DTD?XSD 1.0?XSD 1.1?放松?其他 ...?哦,对了,我看到问题被标记为 XSD,所以我假设您正在寻找 XSD 解决方案。
如果你想说一个orderStatus
元素可以有序列、、或序列作为子元素,并且属性和是可选的,那么在内容模型中这样说很简单。orderId
orderedBy
orderedOn
shipStatus
shipStatus
modifyShipStatus
在 DTD 表示法(我在这里使用它是因为它的紧凑性)你会写:
<!ELEMENT orderStatus ((orderId, orderedBy, orderedOn) | shipStatus) >
<!ATTLIST orderStatus
shipStatus CDATA #IMPLIED
modifyShipStatus CDATA #IMPLIED
>
或者在 XSD 表示法中,写
<xs:element name="orderStatus" type="my:orderStatus"/>
<xs:complexType name="orderStatus">
<xs:choice>
<xs:sequence>
<xs:element ref="my:orderId"/>
<xs:element ref="my:orderedBy"/>
<xs:element ref="my:orderedOn"/>
</xs:sequence>
<xs:element ref="my:shipStatus"/>
</xs:choice>
<xs:attribute name="shipStatus"/>
<xs:attribute name="modifyShipStatus"/>
</xs:complexType>
然后你就完成了。
如果您只想允许这两个属性中的一个,或者如果您希望合法子代取决于是否存在一个或另一个属性,那么事情会更加复杂。(一些文档设计者会说,如果你想要这样,你有两种截然不同的元素类型,你坚持用相同的名称来调用它们,这使得验证变得不必要地困难。)
在这种情况下,您的选择是:
使用如上所述的 DTD 和/或 XSD 1.0 模式,并在文档中或使用 Schematron 或通过其他方法表达附加约束。
使用 XSD 1.1,如上所述定义内容模型和属性,并添加断言来表示
- 正是属性之一
shipStatus
,modifyShipStatus
必须出现。
shipStatus
当且仅当出现一个名为的子项时,该属性必须出现orderId
。
modifyShipStatus
当且仅当出现一个名为的子项时,该属性必须出现shipStatus
。
使用 XSD 1.1,为两种形式的元素定义两种不同的类型,orderStatus
并使用条件类型赋值来说明在以下情况下应用哪种类型:
XSD 看起来像这样:
<xs:complexType name="orderStatus1">
<xs:sequence>
<xs:element ref="my:orderId"/>
<xs:element ref="my:orderedBy"/>
<xs:element ref="my:orderedOn"/>
</xs:sequence>
<xs:attribute name="shipStatus"/>
</xs:complexType>
<xs:complexType name="orderStatus2">
<xs:element ref="my:shipStatus"/>
<xs:attribute name="modifyShipStatus"/>
</xs:complexType>
<xs:element name="orderStatus">
<xs:alternative test="@shipStatus" type="my:orderStatus1"/>
<xs:alternative test="@modifyShipStatus" type="my:orderStatus2"/>
</xs:element>
- 我会顺便指出,它的爱好者经常引用 Relax NG 制定此类约束的能力作为其优势之一。