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

时间:2010-02-18 16:44:50

标签: xml xsd

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

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

我环顾四周,找到了各种解决方案,例如this

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

但是从我的理解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>

但这不是(缺少child3)

<foo>
<child1> value </child1>
<child1> value </child1>
<child2> value </child2>
<child4> value </child4>
<child1> value </child1>
</foo>

6 个答案:

答案 0 :(得分:97)

在后面的编辑中添加的问题的替代公式似乎仍然没有答案:如何在元素的子元素中指定,必须有一个名为child3,一个名为child4,以及名为child1child2的任何数字,对子项出现的顺序没有任何限制。

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

  • 初始状态,其中既没有看到'3'也没有看到'4'
  • 中间状态,其中已经看到'3'而不是'4'
  • 中间状态,其中已经看到'4'而不是'3'
  • 看到“3”和“4”的最终状态

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

(34)|(43)

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

(1|2)*((3(1|2)*4)|(4(1|2)*3))(1|2)*

将其转换为内容模型非常简单。基本结构等同于正则表达式(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>

插入零个或多个child1child2选项非常简单:

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

如果我们想稍微减少批量,我们可以为child1child2的重复选择定义一个命名组:

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

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

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

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

答案 1 :(得分:56)

在问题中的架构中,child1child2可以按任意顺序出现,无论多次。所以这听起来像你在寻找。

修改:如果你只希望其中一个出现无限次,那么无界必须继续使用这些元素:

修改:修复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>

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

答案 3 :(得分:8)

  

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

没有。对于因xs:choice而发生的maxOccurs="unbounded"的每次“重复”,都会单独进行选择。因此,您发布的代码是正确的,并且实际上会按照您所写的方式执行。

答案 4 :(得分:3)

您应该会发现以下架构允许您提出的内容。

  <xs:element name="foo">
    <xs:complexType>
      <xs:sequence minOccurs="0" maxOccurs="unbounded">
        <xs:choice>
          <xs:element maxOccurs="unbounded" name="child1" type="xs:unsignedByte" />
          <xs:element maxOccurs="unbounded" name="child2" type="xs:string" />
        </xs:choice>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

这将允许您创建一个文件,如:

<?xml version="1.0" encoding="utf-8" ?>
<foo>
  <child1>2</child1>
  <child1>3</child1>
  <child2>test</child2>
  <child2>another-test</child2>
</foo>

这似乎与您的问题相符。

答案 5 :(得分:1)

如果以上都不起作用,那么您可能正在开展EDI trasaction,您需要根据HIPPA架构或任何其他复杂的xsd验证结果。 要求是,例如,有8个REF段,其中任何一个都必须以任何顺序出现而且并非所有都是必需的,意味着您可以按照以下顺序排列第一REF,第3 REF,第2 REF,第9 REF。 在默认情况下,EDI接收将失败,因为默认复杂类型为

<xs:sequence>
  <xs:element.../>
</xs:sequence>

当您通过引用调用元素时,情况甚至会很复杂,然后原始位置中的元素本身就非常复杂。 例如:

<xs:element>
<xs:complexType>
<xs:sequence>
<element name="REF1"  ref= "REF1_Mycustomelment" minOccurs="0" maxOccurs="1">
<element name="REF2"  ref= "REF2_Mycustomelment" minOccurs="0" maxOccurs="1">
<element name="REF3"  ref= "REF3_Mycustomelment" minOccurs="0" maxOccurs="1">
</xs:sequence>
</xs:complexType>
</xs:element>

解决方案:

这里简单地用“全部”替换“序列”或用最小/最大组合替换“选择”将不起作用!

首先取代"xs:sequence" with "<xs:all>" 现在,你需要做一些改变你从哪里引用元素, 请转到:

<xs:annotation>
  <xs:appinfo>
    <b:recordinfo structure="delimited" field.........Biztalk/2003">

***现在在上面的段中添加触发点,如下所示trigger_field =“REF01 _...完整名称..”trigger_value =“38” 对触发值不同的其他REF段执行相同操作,例如说“18”,“XX”,“YY”等。所以您的记录信息现在看起来像:b:recordinfo structure="delimited" field.........Biztalk/2003" trigger_field="REF01_...complete name.." trigger_value="38">


这将使每个元素都是唯一的,因为所有REF分段(上例)具有与REF01,REF02,REF03相同的结构。在验证期间,结构验证是可以的,但它不会让值重复,因为它试图在第一个REF本身中查找剩余的值。添加触发器将使它们都是唯一的,它们将以任何顺序和情境情况传递(例如使用5 out 9而不是所有9/9)。

希望它对你有所帮助,因为我花了将近20个小时。

祝你好运