代码之家  ›  专栏  ›  技术社区  ›  Torbjörn Hansson

Xml架构-按任意顺序定义子元素0-*

  •  11
  • Torbjörn Hansson  · 技术社区  · 14 年前

    我想定义一个xml模式,其中元素连接器有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 回复  |  直到 14 年前
        1
  •  30
  •   Torbjörn Hansson    14 年前

    我通过设置 选择 以及设置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>
    
        2
  •  8
  •   jasso    14 年前

    @Torbjrn自己的答案比这个答案更清楚,但是在你最初的尝试中只有一个小小的改变就会产生同样的结果:添加 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" 序列可以一次又一次地重复。

        3
  •  4
  •   jasso    14 年前

    (这不完全是对OP的回答,而是对OP问题的另一个建议答案的回答。作为一个新成员,我不确定这是否打破了一些规则或惯例stackoverflow.com网站. 对不起。)

    不幸的是,在xmlschema中无法定义“这组子元素以任何顺序排列,但每个子元素至少出现一次”。

    你要么被一个定义好的顺序,要么被一个集合中的一个(可能是重复的)卡住了。

    的确,尽管随着元素数量的增加,解决方案会迅速变得庞大。为这样的结构编写一个包含多个元素的模式是很费劲的,容易出错并且很难维护。因此,即使存在一个解决方案,实际实施它是不可能的,也不值得。

    最初的问题只有三个随机出现的元素。正确的解决方案很简单,因为没有一个元素是强制性的。但即使在这种情况下,使用如此小的一组元素,强制每个元素至少出现一次仍然相当容易实现。下面的代码示例

    <?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 root 元素允许多个 Connector 这只是为了让测试不同的组合更容易一些。

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

    问题的复杂性

    <xs:group> 因此,对于这个复杂类型,LOC大约是它的两倍。

    这个有用吗?

    也许 吧。。。不管怎样。对于大型元素集,手动编写并特别是更新这样的结构可能是不合理的。然而,由于所有的群体都有相似的结构 complexType 我想到的一种方法是使用一个函数,它将两个列表(可见和不可见元素)作为参数,然后将所有可见元素添加到第一个列表中 <xs:choice> 元素和为每个不可见的元素创建一个到适当的新状态的转换,然后为每个新引用的状态调用自己。

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

        4
  •  1
  •   dcapelo    7 年前

    这是一个非常古老的线程,但如果这可以帮助这里的任何人是我所做的解决问题。使用xsd:all和对任何可以忽略的子级设置minOccurs=“0”:

    <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>
    
        5
  •  0
  •   Richard    14 年前

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

    你要么被一个定义好的顺序,要么被一个集合中的一个(可能是重复的)卡住了。

    编辑:否 这样,手动生成每一个可能的序列是可能的,而且会起作用,但是组合爆炸会很快失控。