Xml架构 - 以任何顺序定义子元素0- *

时间:2010-08-31 08:50:44

标签: xml xsd

我想定义一个xml架构,其中元素Connectors具有0- *子元素。序列,关联或消息的任何顺序和0到多次。即。

<Connectors>
    <Sequence />
    <Association />
    <Message />
    <Sequence />
    <Sequence />
    <Message />
    <Message />
    <Association />
</Connectors>

我尝试定义以下架构,但似乎订单已修复。

<xs:element name="Connectors">
    <xs:complexType>
        <xs:sequence>
            <xs:element ref="Association" minOccurs="0" maxOccurs="unbounded" />
            <xs:element ref="Message" minOccurs="0" maxOccurs="unbounded" />
            <xs:element ref="Sequence" minOccurs="0" maxOccurs="unbounded" />
        </xs:sequence>
    </xs:complexType>
</xs:element>

5 个答案:

答案 0 :(得分:30)

我通过设置为 choice 并设置minOccurs和maxOccurs属性来解决它。

<xs:element name="Connectors">
    <xs:complexType>
        <xs:choice minOccurs="0" maxOccurs="unbounded">
            <xs:element ref="Association" />
            <xs:element ref="Message" />
            <xs:element ref="Sequence" />
        </xs:choice>
    </xs:complexType>
</xs:element>

答案 1 :(得分:8)

@Torbjörn自己的答案比这个答案更明确,但原始尝试中只有一个小小的变化会产生相同的结果:在maxOccurs="unbounded"元素上添加<xs:sequence>

<xs:element name="Connectors">
    <xs:complexType>
        <xs:sequence maxOccurs="unbounded">
            <xs:element minOccurs="0" name="Association" />
            <xs:element minOccurs="0" name="Message" />
            <xs:element minOccurs="0" name="Sequence" />
        </xs:sequence>
    </xs:complexType>
</xs:element>

确保随机顺序,因为每个元素都有minOccurs="0",并且序列可以一遍又一遍地重复。

答案 2 :(得分:4)

(这不是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元素只允许多个Connector s,以便更轻松地测试不同的组合。

用组元素模仿不同的状态

我已编辑此答案并更新了代码。新的更长,但它是使用基于状态的模式设计的一个非常明显的例子。代码遵循可以验证此问题的有限状态机的不同阶段。所有状态都表示为<xs:group>元素,每个组引用代表所有可能后续状态的其他组。所有<xs:group>元素都遵循相同的结构规则。这些组有两个选择的序列。第一个<xs:choice>是已经看过的元素的无限重复。第二个<xs:choice>包含对表示下一个状态的组的引用之后所有可能的新元素的序列。

问题的复杂性

N个元素的情况可以用具有2 ^ N个不同状态(包括初始状态)的确定性有限状态机来验证。状态将形成N个不同的级别,并且每个级别上的状态量对应于二项式系数,即不同级别上的状态量是“n over k”,其中“n”表示不同元素的数量,“k”表示级别的深度。因为添加一个元素会使所需状态的数量翻倍,所以它也会使<xs:group>的数量翻倍,从而使此复杂类型的LOC大致翻倍。

对此有用吗?

也许......或不。手动编写并特别更新大型元素集的结构可能是不合理的。但是,由于所有组具有相似的结构,因此以编程方式为整个 complexType 结构生成适当的XML模式代码应该相对容易。这样做的一种方法是在我看来是一个函数,它将两个列表作为参数,看到和看不到的元素,然后将所有看到的元素添加到第一个<xs:choice>元素,并且每个看不见的元素创建到适当的新状态的转换然后调用自身对于每个新引用的状态。

请记住,即使生成代码消除了手动跟踪整个结构的痛苦,在大型元素集上,代码大小也会变得如此之大,以至于大小不再合理。一组14个元素需要2 ^ 14 = 16383个组,而在深度级别7,存在最多(14个超过7个)= 3432个并行状态组,每个组具有39个元素(=稍微超过40个LOC)。不,你不想要那样的东西。在这种情况下,您应该开始寻找其他合适的模式定义语言。

答案 3 :(得分:1)

这是一个非常老的线程,但如果这可以帮助这里的任何人是我做的解决问题。使用xsd:all并设置minOccurs =&#34; 0&#34;对任何可以省略的孩子:

<xs:element name="Connectors">
    <xs:complexType>
        <xs:all>
            <xs:element name="Association" minOccurs="0"/>
            <xs:element name="Message" minOccurs="0"/>
            <xs:element name="Sequence"  minOccurs="0"/>
        </xs:all>
    </xs:complexType>
</xs:element>

答案 4 :(得分:0)

不幸的是,在XML Schema中没有实际的方法来定义“这个子元素的任何顺序,但每个元素至少出现一次”。

您可能会遇到已定义的订单或其中一个订单(可能已重复)。

编辑:没有实用的方式,手动生成每个可能的序列是可能的并且可行,但组合爆炸将很快失控。