【问题标题】:How do I write an XML Schema to allow/impose elements to occur one time in any order?如何编写 XML 模式以允许/强制元素以任何顺序出现一次?
【发布时间】:2015-04-04 16:46:58
【问题描述】:

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>

【问题讨论】:

  • 为什么child1不能和child11一起(例子4)而child5可以和child20一起(例子2)?
  • @kjhughes 好地方我没注意到,我认为这是一个错字
  • 是的,很抱歉,现在解决了
  • 这似乎是一个非常常见/有用的 XSD 用例,为什么这不是方案语言的一部分?我是否错误地使用了 XML?
  • 不,你的要求是完全合理的。这是 XML Schema 语言的一个薄弱环节。 XML Schema 非常强调顺序内容(例如,对于复杂类型继承,您只能按顺序附加到基本类型内容)。这确实让那些顺序在 XML 格式中不重要的数据变得困难,这些格式旨在(在某种程度上)供人类读写。

标签: xml xsd


【解决方案1】:

XML Schema 1.0 无法直接解决您的问题。

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

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

我看到了五种可能性:

  1. 在您的问题中使用架构,该架构使用 xs:sequence 而不是 xs:all,但在验证之前使用 XSL 转换按照架构重新排序。
  2. 如果 XML Schema 1.1 是一个选项,您可以定义更宽松的模式(即不强制执行所有规则,但接受所有有效输入的模式),但使用 xs:assert 进行额外检查。
  3. 或者定义一个更宽松的架构,但在架构验证步骤之后在您自己的程序中进行额外检查。
  4. 重构架构,使两组相关元素嵌套在另一个元素下,这样您就可以使用xs:choice。
  5. 将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>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-18
    • 2011-10-09
    • 2012-05-30
    • 1970-01-01
    相关资源
    最近更新 更多