如何编写XML Schema以允许/强制元素以任何顺序出现一次?

时间:2015-04-04 16:46:59

标签: xml xsd

XML有一个父元素parent,它必须包含10个子元素:child1child10,但只有一次。

作为替代方案,parent元素可以选择包含child11child20,而不是child1child10

<parent><child1/><child4/> ... <child2/></parent> OK
<parent><child15/>...<child20/></parent> OK
<parent><child1/><child2/></parent> BAD, missing childs
<parent><child1/>...<child11/></parent> BAD: child11 shall never be with child1
<parent><child1/><child1/></parent> BAD: childs shall not be repeated

到目前为止,这是我的架构定义尝试:

<xs:complexType name="parent">
    <xs:choice>
        <xs:sequence>
            <xs:element name="child1" type="xs:integer" minOccurs="1" maxOccurs="1"/>
            <xs:element name="child2" type="xs:integer" minOccurs="1" maxOccurs="1"/>
            ...
        </xs:sequence>
        <xs:sequence>
            <xs:element name="child11" type="xs:integer" minOccurs="1" maxOccurs="1"/>
            <xs:element name="child12" type="xs:integer" minOccurs="1" maxOccurs="1"/>
            ...
        </xs:sequence>
    </xs:choice>
</xs:complexType>

1 个答案:

答案 0 :(得分:2)

XML Schema 1.0没有直接解决您的问题。

您需要的是以下内容(将xs:sequence替换为xs:all),但这不是有效的XML架构语言:< / p>

<xs:complexType name="parent">
    <xs:choice>
        <xs:all>
            <xs:element name="child1" type="xs:integer" minOccurs="1" maxOccurs="1"/>
            <xs:element name="child2" type="xs:integer" minOccurs="1" maxOccurs="1"/>
            <!-- ... -->
        </xs:all>
        <xs:all>
            <xs:element name="child11" type="xs:integer" minOccurs="1" maxOccurs="1"/>
            <xs:element name="child12" type="xs:integer" minOccurs="1" maxOccurs="1"/>
            <!-- ... -->
        </xs:all>
    </xs:choice>
</xs:complexType>

问题在于xs:choice允许xs:sequencexs:choice合成器的嵌套,而不是xs:all

我看到有五种可能性:

  1. 使用问题中的架构,该架构使用xs:sequence而不是xs:all,但在验证之前使用XSL转换按架构重新排序。
  2. 如果XML Schema 1.1是一个选项,您可以定义一个更宽松的模式(即不强制执行所有规则,但接受所有有效输入的模式),但可以使用{{进行额外检查1}}。
  3. 或者定义一个更宽松的架构,但在架构验证步骤之后,在您自己的程序中执行额外的检查。
  4. 重构架构,使两组相关元素嵌套在另一个元素下,以便您可以使用xs:assert
  5. xs:choice定义为抽象类型,为两个内容模型选择定义派生类型,并使用parent指定在XML文档中使用哪个类型。
  6. 后两个选项都需要更改XML格式。


    如果您可以为元素嵌套添加额外的级别,那么这就是您的架构的外观:

    xsi:type

    如果您使用类型替换,这就是您的架构的外观:

    <xs:complexType name="option1">
        <xs:all>
            <xs:element name="child1" type="xs:integer" minOccurs="1" maxOccurs="1"/>
            <xs:element name="child2" type="xs:integer" minOccurs="1" maxOccurs="1"/>
            <!-- ... -->
        </xs:all>
    </xs:complexType>
    
    <xs:complexType name="option2">
        <xs:all>
            <xs:element name="child11" type="xs:integer" minOccurs="1" maxOccurs="1"/>
            <xs:element name="child12" type="xs:integer" minOccurs="1" maxOccurs="1"/>
            <!-- ... -->
        </xs:all>
    </xs:complexType>
    
    <xs:complexType name="parent">
        <xs:choice>
            <xs:element name="option1" type="option1"/>
            <xs:element name="option2" type="option2"/>
        </xs:choice>
    </xs:complexType>
    

    使用此方法的XML实例文档对于您的第一组元素看起来如下所示(请注意使用<xs:complexType name="parent" abstract="true"> </xs:complexType> <xs:complexType name="parent_option1"> <xs:complexContent> <xs:extension base="parent"> <xs:all> <xs:element name="child1" type="xs:integer" minOccurs="1" maxOccurs="1"/> <xs:element name="child2" type="xs:integer" minOccurs="1" maxOccurs="1"/> <!-- ... --> </xs:all> </xs:extension> </xs:complexContent> </xs:complexType> <xs:complexType name="parent_option2"> <xs:complexContent> <xs:extension base="parent"> <xs:all> <xs:element name="child11" type="xs:integer" minOccurs="1" maxOccurs="1"/> <xs:element name="child12" type="xs:integer" minOccurs="1" maxOccurs="1"/> <!-- ... --> </xs:all> </xs:extension> </xs:complexContent> </xs:complexType> <xs:element name="parent" type="parent"/> 指定已选择的组):

    xsi:type

    对于第二组:

    <parent
        xmlns="Your namespace here"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:type="parent_option1">
    
        <child2>2</child2>
        <child1>1</child1>
        <!-- ... -->
    
    </parent>