如何描述XML模式中集合/复合类型的选择?

如何描述XML模式中集合/复合类型的选择?,xml,xsd,Xml,Xsd,我有一个类似于下面的XML文档,其中有两种类型的元素。第一种类型只能包含一些有序的节点集;第二种类型只能包含一些其他有序的节点集。这些都混合在根元素下。例如: <root> <!-- any number of Type One and Type Two --> <item> <type>Type One</type> <a /> <b /> </item> &

我有一个类似于下面的XML文档,其中有两种类型的元素。第一种类型只能包含一些有序的节点集;第二种类型只能包含一些其他有序的节点集。这些都混合在根元素下。例如:

<root>
  <!-- any number of Type One and Type Two -->
  <item>
    <type>Type One</type>
    <a />
    <b />
  </item>
  <item>
    <type>Type Two</type>
    <d />
    <e />
  </item>
</root>

第一类
:


最简单、技术上最好的方法是更改显示的XML表单。您有两种不同类型的元素;给他们两个不同的名字。然后,您的样本将采用如下形式:

<root>
  <!-- any number of TypeOne and TypeTwo elements -->
  <typeOne>
    <a />
    <b />
  </typeOne>
  <typeTwo>
    <d />
    <e />
  </typeTwo>
</root>
<element name="root" type="tns:root"/>
<element name="item" type="tns:item"/>
<complexType name="root">
  <choice minOccurs="0" maxOccurs="unbounded">
    <element ref="tns:item"/>
  </choice>
</complexType>
<complexType name="item">
  <choice>
    <sequence>
      <element ref="tns:flag1"/>
      <element ref="tns:a"/>
      <element ref="tns:b"/>
    </sequence>
    <sequence>
      <element ref="tns:flag2"/>
      <element ref="tns:d"/>
      <element ref="tns:e"/>
    </sequence>
  </choice>
</complexType>
<?xml version="1.0" encoding="UTF-8"?>
<schema 
  xmlns="http://www.w3.org/2001/XMLSchema"
  xmlns:tns="http://example.com/tns"
  targetNamespace="http://example.com/tns"
  elementFormDefault="qualified"> 

  <element name="root" type="tns:root"/>
  <element name="item" type="tns:typeOne-or-typeTwo"/>
  <element name="type" type="tns:typestring"/>
  <element name="a"/>
  <element name="b"/>
  <element name="d"/>
  <element name="e"/>

  <simpleType name="typestring">
    <restriction base="string">
      <enumeration value="Type One"/>
      <enumeration value="Type Two"/>
    </restriction>
  </simpleType>

  <complexType name="root">
    <sequence>
      <element ref="tns:item" maxOccurs="unbounded"/>
        </sequence>
  </complexType>

  <complexType name="typeOne-or-typeTwo">
    <sequence>
      <element ref="tns:type"/>
      <choice>
        <sequence>
          <element ref="tns:a"/>
          <element ref="tns:b"/>
        </sequence>
        <sequence>
          <element ref="tns:d"/>
          <element ref="tns:e"/>
        </sequence>
      </choice>      
    </sequence>
    <assert test="(string(./tns:type) = 'Type One' 
                       and child::*[2]/self::tns:a)
                   or
                  (string(./tns:type) = 'Type Two' 
                       and child::*[2]/self::tns:d)">
      <annotation>
        <documentation>
          If the initial 'type' element contains the string 
          'Type One', then the next child should be 
          element 'a' (followed in any valid instance
          by a 'b'); if the initial 'type' element contains 
          the string 'Type Two', then the next child should 
          be element 'd'.  Etc.
        </documentation>
      </annotation>
    </assert>    
  </complexType>
</schema>
在您的评论中,您添加了您正在尝试将XML与现有数据流相匹配的内容,该数据流与您在问题中显示的XML基本相同。我上面所说的仍然适用:最简单和最好的方法是修复XML的破损设计。但是,如果我们假设您不能或不会说服XML数据流的生产者生成结构不那么反常的东西,那么您最好的选择可能是使用XSD 1.1断言来约束结构。这使得其他XSD工具(如数据绑定工具)的工作更加困难,因为理解断言的含义非常类似于在一个不太容易理解的形式逻辑中证明定理,而且大多数数据绑定工具或编辑器将无法对模式做太多工作

但您可以通过以下方式验证您的输入:

<root>
  <!-- any number of TypeOne and TypeTwo elements -->
  <typeOne>
    <a />
    <b />
  </typeOne>
  <typeTwo>
    <d />
    <e />
  </typeTwo>
</root>
<element name="root" type="tns:root"/>
<element name="item" type="tns:item"/>
<complexType name="root">
  <choice minOccurs="0" maxOccurs="unbounded">
    <element ref="tns:item"/>
  </choice>
</complexType>
<complexType name="item">
  <choice>
    <sequence>
      <element ref="tns:flag1"/>
      <element ref="tns:a"/>
      <element ref="tns:b"/>
    </sequence>
    <sequence>
      <element ref="tns:flag2"/>
      <element ref="tns:d"/>
      <element ref="tns:e"/>
    </sequence>
  </choice>
</complexType>
<?xml version="1.0" encoding="UTF-8"?>
<schema 
  xmlns="http://www.w3.org/2001/XMLSchema"
  xmlns:tns="http://example.com/tns"
  targetNamespace="http://example.com/tns"
  elementFormDefault="qualified"> 

  <element name="root" type="tns:root"/>
  <element name="item" type="tns:typeOne-or-typeTwo"/>
  <element name="type" type="tns:typestring"/>
  <element name="a"/>
  <element name="b"/>
  <element name="d"/>
  <element name="e"/>

  <simpleType name="typestring">
    <restriction base="string">
      <enumeration value="Type One"/>
      <enumeration value="Type Two"/>
    </restriction>
  </simpleType>

  <complexType name="root">
    <sequence>
      <element ref="tns:item" maxOccurs="unbounded"/>
        </sequence>
  </complexType>

  <complexType name="typeOne-or-typeTwo">
    <sequence>
      <element ref="tns:type"/>
      <choice>
        <sequence>
          <element ref="tns:a"/>
          <element ref="tns:b"/>
        </sequence>
        <sequence>
          <element ref="tns:d"/>
          <element ref="tns:e"/>
        </sequence>
      </choice>      
    </sequence>
    <assert test="(string(./tns:type) = 'Type One' 
                       and child::*[2]/self::tns:a)
                   or
                  (string(./tns:type) = 'Type Two' 
                       and child::*[2]/self::tns:d)">
      <annotation>
        <documentation>
          If the initial 'type' element contains the string 
          'Type One', then the next child should be 
          element 'a' (followed in any valid instance
          by a 'b'); if the initial 'type' element contains 
          the string 'Type Two', then the next child should 
          be element 'd'.  Etc.
        </documentation>
      </annotation>
    </assert>    
  </complexType>
</schema>

如果初始“type”元素包含字符串
“键入一”,则下一个子项应为
元素“a”(后跟任何有效实例
a‘b’;如果初始“type”元素包含
字符串“typetwo”,则下一个子项应
是元素“d”。等

这确实需要XSD 1.1支持,可从Saxon、Xerces和XMLSpy获得。

Hm、OTOH、3的
序列
:类型1、类型2,然后是包含类型1和类型2的
选项的complextype,并使该complextype minoccurs=0,maxoccurs=unbounded?@Wrikken:这不是我想要描述的结构——根节点包含任意数量的类型
type One
type Two
。好吧,我当时误解了你的意思,我想应该先显式地要求type 1,然后才是type 2,然后将它们中的任何一个设置为0-unlimited。但是我真的不明白你的问题:有没有一个选项可以包含complextypes?=>@Wrikken:为了更好地描述这个问题,我更新了这个问题——如果你只是把这些类型的元素放在
xs:choice
下,那么你就打破了唯一的粒子属性规则。不幸的是,“最简单的事情”是不好的,因为我正在将一个模式改装到一个以前定义为“无论库X理解什么”:(那么您可能需要编辑您的问题,以明确您的实际约束。呃,我认为问题非常清楚。它说的是“我想匹配此文档”,而不是“我想匹配与此文档不同的内容”。“
我假设您知道如何为所有这些内容编写内容模型。
<root>
  <!-- any number of TypeOne and TypeTwo elements,
       but we call them all by the same name -->
  <item>
    <a />
    <b />
  </item>
  <item>
    <d />
    <e />
  </item>
</root>
<?xml version="1.0" encoding="UTF-8"?>
<schema 
  xmlns="http://www.w3.org/2001/XMLSchema"
  xmlns:tns="http://example.com/tns"
  targetNamespace="http://example.com/tns"
  elementFormDefault="qualified"> 

  <element name="root" type="tns:root"/>
  <element name="item" type="tns:typeOne-or-typeTwo"/>
  <element name="type" type="tns:typestring"/>
  <element name="a"/>
  <element name="b"/>
  <element name="d"/>
  <element name="e"/>

  <simpleType name="typestring">
    <restriction base="string">
      <enumeration value="Type One"/>
      <enumeration value="Type Two"/>
    </restriction>
  </simpleType>

  <complexType name="root">
    <sequence>
      <element ref="tns:item" maxOccurs="unbounded"/>
        </sequence>
  </complexType>

  <complexType name="typeOne-or-typeTwo">
    <sequence>
      <element ref="tns:type"/>
      <choice>
        <sequence>
          <element ref="tns:a"/>
          <element ref="tns:b"/>
        </sequence>
        <sequence>
          <element ref="tns:d"/>
          <element ref="tns:e"/>
        </sequence>
      </choice>      
    </sequence>
    <assert test="(string(./tns:type) = 'Type One' 
                       and child::*[2]/self::tns:a)
                   or
                  (string(./tns:type) = 'Type Two' 
                       and child::*[2]/self::tns:d)">
      <annotation>
        <documentation>
          If the initial 'type' element contains the string 
          'Type One', then the next child should be 
          element 'a' (followed in any valid instance
          by a 'b'); if the initial 'type' element contains 
          the string 'Type Two', then the next child should 
          be element 'd'.  Etc.
        </documentation>
      </annotation>
    </assert>    
  </complexType>
</schema>