我试图使两个 XML 属性互斥。如何创建 XSD 模式来捕获这种场景?
我想要其中之一
<elem value="1" />
<elem ref="something else" />
但不是
<elem value="1" ref="something else" />
我试图使两个 XML 属性互斥。如何创建 XSD 模式来捕获这种场景?
我想要其中之一
<elem value="1" />
<elem ref="something else" />
但不是
<elem value="1" ref="something else" />
您不能使用属性,但可以使用子元素...
<element name="elem">
<complexType>
<choice>
<element name="value"/>
<element name="ref"/>
</choice>
</complexType>
</element>
这样你就可以拥有...
<elem>
<value>1</value>
</elem>
或者...
<elem>
<rel>something else</rel>
</elem>
不幸的是,AFAIK 你不能用 XML Schema 做到这一点,我自己也遇到了同样的问题。
我已经看到它建议如果您需要两者:
<elem type="xxx">
<elem ref="yyy">
那么<elem>
本身应该分为两种类型,因为它们显然具有不同的属性...
由于在 Alnitak 的回答中提到了RelaxNG ,这里有一个使用 RelaxNG 的解决方案(一种在大多数情况下比 W3C Schema 更好的语言)。请注意 elem 定义中的 OR (|):
start = document
document = element document {elem+}
elem = element elem {ref | value}
ref = attribute ref {text}
value = attribute value {xsd:integer}
如果我有这个 XML 文件:
<document>
<elem value="1" />
<elem ref="something else" />
</document>
% rnv attributes-exclusive.rnc attributes-exclusive.xml
attributes-exclusive.xml
% xmllint --noout --relaxng attributes-exclusive.rng attributes-exclusive.xml
attributes-exclusive.xml validates
如果我在 XML 文件中添加:
<elem value="1" ref="something else" />
我得到了我想要的验证错误(请注意错误消息不是最理想的):
% rnv attributes-exclusive.rnc attributes-exclusive.xml
attributes-exclusive.xml
attributes-exclusive.xml:4:0: error: attribute ^ref not allowed
required:
after
% xmllint --noout --relaxng attributes-exclusive.rng attributes-exclusive.xml
attributes-exclusive.xml:4: element elem: Relax-NG validity error : Invalid attribute value for element elem
attributes-exclusive.xml fails to validate
实际上,可以通过 xs:unique 或 xs:key 使用身份约束在 XSD 1.0 中定义它。您选择哪一个取决于如何处理没有这两个属性中的任何一个的元素:它们对 xs:unique 有效,但对 xs:key 无效。下面的代码示例包含两种变体;确保删除其中一个,否则“更严格”的 xs:key 优先于 xs:unique,即需要两个属性之一。
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="container">
<xs:complexType>
<xs:sequence>
<xs:element name="elem" maxOccurs="unbounded">
<xs:complexType>
<xs:attribute name="value" use="optional"/>
<xs:attribute name="ref" use="optional"/>
</xs:complexType>
<!-- Note: Use either xs:unique or xs:key -->
<xs:unique name="attrsExclusiveOptional">
<xs:annotation>
<xs:documentation>Ensure that @value and @ref cannot occur simultaneously.
Both may be omitted.</xs:documentation>
</xs:annotation>
<xs:selector xpath="."/>
<xs:field xpath="@value | @ref"/>
</xs:unique>
<xs:key name="attrsExclusiveRequired">
<xs:annotation>
<xs:documentation>Ensure that @value and @ref cannot occur simultaneously.
One of them is required.</xs:documentation>
</xs:annotation>
<xs:selector xpath="."/>
<xs:field xpath="@value | @ref"/>
</xs:key>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
这将验证以下 XML 文件:
<?xml version="1.0" encoding="UTF-8"?>
<container xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="schema.xsd">
<!-- Shall pass: -->
<elem value="1" />
<elem ref="something else" />
<!-- Passes for xs:unique, fails for xs:key: -->
<elem />
<!-- Shall fail: -->
<elem value="1" ref="something else" />
</container>
XSD 对此有抽象类型:http ://www.tek-tips.com/viewthread.cfm?qid= 1364846(参见 tsuji 的帖子)
基本上,您为手头的元素提供一个abstract、复杂的类型,并在其中定义它的通用属性,对于所有不同的用例,这些属性完全相同(您的示例不需要)。
然后创建 2 个(或更多)额外的复杂类型来扩展我刚才提到的抽象类型。在这些新类型中,您可以在每个用例之间定义不同的属性集。XSD 部分就是这样。
最后,您需要将 XSItype
属性添加到模式实例文档中的结果元素。因此,要有效,该元素现在必须具有一组属性或另一组属性。
不是直截了当,而是灵活,众所周知:越灵活,事情就越困难。
对于稍后阅读此内容的读者,请注意该问题可以在 XSD 1.1 中使用“条件类型分配”或断言来解决。