如何将 XML 架构写入 allow/impose 元素以任何顺序出现一次?
How do I write an XML Schema to allow/impose elements to occur one time in any order?
XML 有一个父元素 parent
,它必须包含 10 个子元素:child1
到 child10
,顺序不限,但只有一次。
作为替代方案,parent
元素可以选择包含 child11
到 child20
而不是 child1
到 child10
。
<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:sequence
和 xs:choice
合成器,但不允许 xs:all
。
我看到了五种可能性:
- 使用问题中的模式,它使用
xs:sequence
而不是 xs:all
,但在验证之前使用 XSL 转换根据模式重新排序。
- 如果 XML 模式 1.1 是一个选项,您可以定义一个更宽松的模式(即不强制执行所有规则但接受所有有效输入的模式),但获得额外的使用
xs:assert
. 检查
- 或者定义一个更宽松的模式,但在模式验证步骤之后在您自己的程序中进行额外检查。
- 重组架构,使两组相关元素嵌套在另一个元素下,这样就可以使用
xs:choice
.
- 将
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>
XML 有一个父元素 parent
,它必须包含 10 个子元素:child1
到 child10
,顺序不限,但只有一次。
作为替代方案,parent
元素可以选择包含 child11
到 child20
而不是 child1
到 child10
。
<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:sequence
和 xs:choice
合成器,但不允许 xs:all
。
我看到了五种可能性:
- 使用问题中的模式,它使用
xs:sequence
而不是xs:all
,但在验证之前使用 XSL 转换根据模式重新排序。 - 如果 XML 模式 1.1 是一个选项,您可以定义一个更宽松的模式(即不强制执行所有规则但接受所有有效输入的模式),但获得额外的使用
xs:assert
. 检查
- 或者定义一个更宽松的模式,但在模式验证步骤之后在您自己的程序中进行额外检查。
- 重组架构,使两组相关元素嵌套在另一个元素下,这样就可以使用
xs:choice
. - 将
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>