如何将 XML 架构写入 allow/impose 元素以任何顺序出现一次?

How do I write an XML Schema to allow/impose elements to occur one time in any order?

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>

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

您想要的是以下内容(将 xs:sequence 替换为 xs:all),但是 这是无效的 XML 模式语言:

<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 模式 1.1 是一个选项,您可以定义一个更宽松的模式(即不强制执行所有规则但接受所有有效输入的模式),但获得额外的使用 xs:assert.
  3. 检查
  4. 或者定义一个更宽松的模式,但在模式验证步骤之后在您自己的程序中进行额外检查。
  5. 重组架构,使两组相关元素嵌套在另一个元素下,这样就可以使用xs:choice.
  6. parent定义为抽象类型,为两种选择的内容模型定义派生类型,并使用xsi:type指定XML文档中使用的是哪一种。

不幸的是,后两个选项都需要更改 XML 格式。


如果您可以向元素嵌套添加额外的层次,您的模式可能会是这样的:

<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>

如果您使用类型替换,您的模式可能会是这样的:

<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"/>

使用此方法的 XML 实例文档对于您的第一组元素如下所示(请注意使用 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>

第二组:

<parent
    xmlns="Your namespace here"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:type="parent_option2">

    <child11>11</child11>
    <child12>12</child12>
    <!-- ... -->

</parent>