(这不完全是对 OP 的回答,而是对 OP 问题的另一个建议答案的回答。作为一个全新的成员,我不确定这是否违反了 stackoverflow.com 上的一些规则或约定。抱歉。 )
正如用户@Richard 在他的回答中所写:
不幸的是,在 XML Schema 中没有办法定义“这组子元素以任何顺序但每个至少出现一次”。
您被固定的顺序或一组中的一个(可能重复)所困。
没有标签或属性特别允许这种结构是正确的,但是引用的文本在理论上不是正确的,尽管随着元素数量的增加,解决方案很快就会变得庞大。为这种包含多个元素的结构编写模式非常费力、容易出错且难以维护。因此,即使存在解决方案,实际实施也不可能也不值得。
原始海报问题只有一组随机出现的三个元素。正确的解决方案很简单,因为没有一个元素是强制性的。但即使在这种情况下,使用这么少的元素集,强制每个元素至少出现一次仍然比较容易实现。下面的代码示例
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- Schema for 3 elements with random order.
Each element must appear at least once. -->
<xs:element name="Association" type="xs:string"/>
<xs:element name="Message" type="xs:string"/>
<xs:element name="Sequence" type="xs:string"/>
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="Connectors" type="unordered-3-group" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="unordered-3-group">
<!-- state level 0 -->
<xs:group ref="Connectors-state-0"/>
</xs:complexType>
<xs:group name="Connectors-state-0">
<xs:sequence>
<!-- Empty, no previous elements
<xs:choice minOccurs="0" maxOccurs="unbounded">
</xs:choice> -->
<xs:choice>
<xs:sequence>
<xs:element ref="Association"/>
<xs:group ref="Connectors-state-1a"/>
</xs:sequence>
<xs:sequence>
<xs:element ref="Message"/>
<xs:group ref="Connectors-state-1b"/>
</xs:sequence>
<xs:sequence>
<xs:element ref="Sequence"/>
<xs:group ref="Connectors-state-1c"/>
</xs:sequence>
</xs:choice>
</xs:sequence>
</xs:group>
<xs:group name="Connectors-state-1a">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="Association"/>
</xs:choice>
<xs:choice>
<xs:sequence>
<xs:element ref="Message" />
<xs:group ref="Connectors-state-2a"/>
</xs:sequence>
<xs:sequence>
<xs:element ref="Sequence" />
<xs:group ref="Connectors-state-2b"/>
</xs:sequence>
</xs:choice>
</xs:sequence>
</xs:group>
<xs:group name="Connectors-state-1b">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="Message"/>
</xs:choice>
<xs:choice>
<xs:sequence>
<xs:element ref="Association" />
<xs:group ref="Connectors-state-2a"/>
</xs:sequence>
<xs:sequence>
<xs:element ref="Sequence" />
<xs:group ref="Connectors-state-2c"/>
</xs:sequence>
</xs:choice>
</xs:sequence>
</xs:group>
<xs:group name="Connectors-state-1c">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="Sequence"/>
</xs:choice>
<xs:choice>
<xs:sequence>
<xs:element ref="Association" />
<xs:group ref="Connectors-state-2b"/>
</xs:sequence>
<xs:sequence>
<xs:element ref="Message" />
<xs:group ref="Connectors-state-2c"/>
</xs:sequence>
</xs:choice>
</xs:sequence>
</xs:group>
<xs:group name="Connectors-state-2a">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="Association"/>
<xs:element ref="Message"/>
</xs:choice>
<xs:choice>
<xs:sequence>
<xs:element ref="Sequence" />
<xs:group ref="Connectors-state-3a"/>
</xs:sequence>
</xs:choice>
</xs:sequence>
</xs:group>
<xs:group name="Connectors-state-2b">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="Association"/>
<xs:element ref="Sequence"/>
</xs:choice>
<xs:choice>
<xs:sequence>
<xs:element ref="Message" />
<xs:group ref="Connectors-state-3a"/>
</xs:sequence>
</xs:choice>
</xs:sequence>
</xs:group>
<xs:group name="Connectors-state-2c">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="Message"/>
<xs:element ref="Sequence"/>
</xs:choice>
<xs:choice>
<xs:sequence>
<xs:element ref="Association" />
<xs:group ref="Connectors-state-3a"/>
</xs:sequence>
</xs:choice>
</xs:sequence>
</xs:group>
<xs:group name="Connectors-state-3a">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="Association"/>
<xs:element ref="Message"/>
<xs:element ref="Sequence"/>
</xs:choice>
<!-- Empty, no new elements
<xs:choice>
<xs:sequence>
</xs:sequence>
</xs:choice> -->
</xs:sequence>
</xs:group>
</xs:schema>
Connectors 就像 OP 一样用作容器。单独的root 元素允许多个Connectors,只是为了更容易测试不同的组合。
用组元素模仿不同的状态
我已编辑此答案并更新了代码。新的更长,但它是利用基于状态的模式设计的一个非常明显的例子。代码遵循可以验证此问题的有限状态机的不同阶段。所有状态都表示为<xs:group> 元素,每个组引用代表所有可能的后续状态的其他组。所有<xs:group> 元素的结构都遵循相同的规则。这些组有两个选择的序列。第一个<xs:choice> 是已经看到的元素的无限重复。第二个<xs:choice> 包含所有可能的新元素的序列,这些元素在对表示下一个状态的组的引用之后。
问题的复杂性
可以使用具有 2^N 个不同状态(包括初始状态)的确定性有限状态机来验证 N 个元素的情况。状态将形成 N 个不同的级别,每个级别上的状态数量对应于二项式系数,即不同级别上的状态数量为“n over k”,其中“n”表示不同元素的数量,“k”表示级别的深度。因为再添加一个元素会使所需状态的数量增加一倍,所以<xs:group>s 的数量也会增加一倍,因此这种复杂类型的 LOC 大致会增加一倍。
这个有什么用吗?
也许……也许不是。为大型元素集手动编写尤其是更新这种结构可能是不合理的。然而,由于所有组都具有相似的结构以编程方式为整体生成适当的 XML Schema 代码应该相对容易complexType结构。其中一种方法是我的头脑是一个函数,它接受两个列表作为参数,看到和未看到的元素,然后将所有看到的元素添加到第一个 <xs:choice> 元素,并为每个未看到的元素创建一个到适当新状态的转换,然后为每个新引用的元素调用自身状态。
请记住,即使生成代码消除了手动跟踪整个结构的痛苦,但在大型元素集上,代码大小会变得如此之大,以至于大小不再合理。一组 14 个元素需要 2^14 = 16383 个组,在深度级别 7 处,最多有(14 over 7)= 3432 个并行状态组,每个组有 39 个元素(= 略高于 40 LOC)。不,你不想要那样的东西。在这种情况下,您应该开始寻找其他合适的架构定义语言。