XSD - 如何允许任何次序的元素?

jvt*_*ech 102 xml xsd

我正在尝试创建一个XSD,并尝试使用以下要求编写定义:

  • 允许指定的子元素出现任意次数(0到无界)
  • 允许子元素按任何顺序排列

我环顾四周,发现像各种解决方案这样:

<xs:element name="foo">
  <xsl:complexType>
    <xs:choice minOccurs="0" maxOccurs="unbounded">
      <xs:element name="child1" type="xs:int"/>
      <xs:element name="child2" type="xs:string"/>
    </xs:choice>
  </xs:complexType>
</xs:element>
Run Code Online (Sandbox Code Playgroud)

但据我所知xs:choice仍然只允许单个元素选择.因此,将MaxOccurs设置为无界限应该只意味着子元素中的"任何一个"可以多次出现.这准确吗?

如果上述解决方案不正确,我怎样才能实现我在上述要求中所说的内容?

编辑:如果要求如下,该怎么办?

  • 元素child1 child2可以出现任意次数(0到无界)
  • 元素以任何顺序排列
  • 元素child3和child4应该只出现一次.

例如,此xml有效:

<foo>
<child1> value </child1>
<child1> value </child1>
<child3> value </child3>
<child2> value </child2>
<child4> value </child4>
<child1> value </child1>
</foo>
Run Code Online (Sandbox Code Playgroud)

但这不是(缺少孩子3)

<foo>
<child1> value </child1>
<child1> value </child1>
<child2> value </child2>
<child4> value </child4>
<child1> value </child1>
</foo>
Run Code Online (Sandbox Code Playgroud)

C. *_*een 101

在后面的编辑中添加的问题的替代公式似乎仍然没有答案:如何在元素的子元素中指定必须有一个命名child3,一个命名child4,以及任何命名的数字,child1或者child2对顺序没有约束孩子们出现了什么.

这是一种直接可定义的常规语言,您需要的内容模型与定义字符串集的正则表达式是同构的,其中数字'3'和'4'各自恰好出现一次,数字'1'和'2 '发生了很多次.如果不清楚如何写这个,那么考虑建立什么样的有限状态机以识别这种语言可能会有所帮助.它至少有四种不同的状态:

  • 一个初始状态,其中既没有看到'3'也没有看到'4'
  • 一个中间状态,其中'3'已被看到但不是'4'
  • 一个中间状态,其中'4'已被看到但不是'3'
  • 已经看到"3"和"4"的最终状态

无论自动机处于什么状态,都可以读取"1"和"2"; 他们不会改变机器的状态.在初始状态,'3'或'4'也将被接受; 在中间状态,只接受'4'或'3'; 在最终状态下,"3"和"4"都不被接受.如果我们首先为我们语言的子集定义正则表达式,那么正则表达式的结构最容易理解,其中只出现"3"和"4":

(34)|(43)
Run Code Online (Sandbox Code Playgroud)

为了允许'1'或'2'在给定位置发生任意次数,我们可以插入(1|2)*(或者[12]*如果我们的正则表达式语言接受该表示法).我们得到了在所有可用位置插入此表达式

(1|2)*((3(1|2)*4)|(4(1|2)*3))(1|2)*
Run Code Online (Sandbox Code Playgroud)

将其转换为内容模型非常简单.基本结构相当于正则表达式(34)|(43):

<xsd:complexType name="paul0">
  <xsd:choice>
    <xsd:sequence>
      <xsd:element ref="child3"/>
      <xsd:element ref="child4"/>
    </xsd:sequence>
    <xsd:sequence>
      <xsd:element ref="child4"/>
      <xsd:element ref="child3"/>
    </xsd:sequence>
  </xsd:choice>
</xsd:complexType>
Run Code Online (Sandbox Code Playgroud)

插入零或多个选项child1并且child2很简单:

<xsd:complexType name="paul1">
  <xsd:sequence>
    <xsd:choice minOccurs="0" maxOccurs="unbounded">
      <xsd:element ref="child1"/>
      <xsd:element ref="child2"/>
    </xsd:choice>      
    <xsd:choice>
      <xsd:sequence>
        <xsd:element ref="child3"/>
        <xsd:choice minOccurs="0" maxOccurs="unbounded">
          <xsd:element ref="child1"/>
          <xsd:element ref="child2"/>
        </xsd:choice>      
        <xsd:element ref="child4"/>
      </xsd:sequence>
      <xsd:sequence>
        <xsd:element ref="child4"/>
        <xsd:choice minOccurs="0" maxOccurs="unbounded">
          <xsd:element ref="child1"/>
          <xsd:element ref="child2"/>
        </xsd:choice>      
        <xsd:element ref="child3"/>
      </xsd:sequence>
    </xsd:choice>
    <xsd:choice minOccurs="0" maxOccurs="unbounded">
      <xsd:element ref="child1"/>
      <xsd:element ref="child2"/>
    </xsd:choice>      
  </xsd:sequence>
</xsd:complexType>
Run Code Online (Sandbox Code Playgroud)

如果我们想最大限度地减少批量,我们可以为重复选择child1和定义一个命名组child2:

<xsd:group name="onetwo">
  <xsd:choice>
    <xsd:element ref="child1"/>
    <xsd:element ref="child2"/>
  </xsd:choice>   
</xsd:group>

<xsd:complexType name="paul2">
  <xsd:sequence>
    <xsd:group ref="onetwo" minOccurs="0" maxOccurs="unbounded"/>
    <xsd:choice>
      <xsd:sequence>
        <xsd:element ref="child3"/>
        <xsd:group ref="onetwo" minOccurs="0" maxOccurs="unbounded"/>
        <xsd:element ref="child4"/>
      </xsd:sequence>
      <xsd:sequence>
        <xsd:element ref="child4"/>
        <xsd:group ref="onetwo" minOccurs="0" maxOccurs="unbounded"/>
        <xsd:element ref="child3"/>
      </xsd:sequence>
    </xsd:choice>  
    <xsd:group ref="onetwo" minOccurs="0" maxOccurs="unbounded"/>
  </xsd:sequence>
</xsd:complexType>
Run Code Online (Sandbox Code Playgroud)

在XSD 1.1中,对all-groups的一些约束已被取消,因此可以更简洁地定义此内容模型:

<xsd:complexType name="paul3">
  <xsd:all>
    <xsd:element ref="child1" minOccurs="0" maxOccurs="unbounded"/>
    <xsd:element ref="child2" minOccurs="0" maxOccurs="unbounded"/>
    <xsd:element ref="child3"/>
    <xsd:element ref="child4"/>      
  </xsd:all>
</xsd:complexType>
Run Code Online (Sandbox Code Playgroud)

但是从前面给出的例子中可以看出,这些对all群组的改变实际上并没有改变语言的表达能力; 他们只是使某些语言的定义更加简洁.

  • +1.这是一个很好的答案,值得更多的赞成. (8认同)
  • 我喜欢XSD 1.0 xs:所有选择. (3认同)
  • 迈克尔,你说"这些对所有群体的改变实际上并没有改变语言的表达能力;它们只会使某些语言的定义更加简洁".但是如果你把问题推广到任意数量的子元素,其中一个子集可以出现一次,另一个子集可以出现任意次数,那么XSD 1.0解决方案会产生组合爆炸,不是吗?虽然XSD 1.1解决方案仍然保持清洁. (2认同)

xcu*_*cut 57

在您的问题中的模式中,child1或者child2可以按任何顺序出现,无论多少次.所以这听起来像你在寻找.

编辑:如果你只希望其中一个出现无限次,那么无界将不得不继续使用这些元素:

编辑:修复XML格式.

编辑: maxOccurs中的大写O.

<xs:element name="foo">
   <xs:complexType>
     <xs:choice maxOccurs="unbounded">
       <xs:element name="child1" type="xs:int" maxOccurs="unbounded"/>
       <xs:element name="child2" type="xs:string" maxOccurs="unbounded"/>
     </xs:choice>
   </xs:complexType>
</xs:element>
Run Code Online (Sandbox Code Playgroud)

  • jvtech:你不能满足XML模式的编辑要求; 实现它的唯一方法是,如果child3和child4只能在结尾出现.在这种情况下,您需要一个包含选项的序列,然后是两个元素. (2认同)
  • @Daij-Djan 我还发现它不起作用。尝试在 choice 元素上添加 maxOccurs="unbounded" ,以便允许多个子元素。 (2认同)

小智 47

这最终对我有用:

<xsd:element name="bar">
  <xsd:complexType>
    <xsd:sequence>
      <!--  Permit any of these tags in any order in any number     -->
      <xsd:choice minOccurs="0" maxOccurs="unbounded">
        <xsd:element name="child1" type="xsd:string" />
        <xsd:element name="child2" type="xsd:string" />
        <xsd:element name="child3" type="xsd:string" />
      </xsd:choice>
    </xsd:sequence>
  </xsd:complexType>
</xsd:element>
Run Code Online (Sandbox Code Playgroud)

  • 我认为值得指出的是,即使没有包含choice-element的sequence-element,上面的示例也能正常工作. (6认同)
  • 确实诀窍是使用xsd:choice和quantiers <xsd:choice minOccurs ="0"maxOccurs ="unbounded"> (5认同)
  • 这是否违反了操作的“元素 child3 和 child4 应该只出现一次”的约束? (2认同)

Pav*_*aev 8

但据我所知xs:choice仍然只允许单个元素选择.因此,将MaxOccurs设置为无界限应该只意味着子元素中的"任何一个"可以多次出现.这准确吗?

不会.选择是因为每次"重复"而单独xs:choice发生的maxOccurs="unbounded".因此,您发布的代码是正确的,并且实际上会按照您所写的方式执行.