XSD-如何允许元素以任意顺序多次出现?


109

我正在尝试创建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>

但是据我了解,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>

Answers:


61

在您的问题中存在的架构中,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>

基本上是的,我正在寻找元素child1,child2以任何顺序出现任何次数。.您在此处提供的答案仅适用于单个元素,对吗?还是可以解决我的要求?
jvtech 2010年

您问题中的模式符合您的要求;我的答案中的替代方案是针对单个元素。希望能清除它!:)
xcut

@ Pavel,@ xcut,感谢您的澄清,请参阅已编辑的要求。
jvtech

2
jvtech:您无法使用XML模式满足该编辑要求;唯一的方法是child3和child4只能出现在最后。在这种情况下,您需要一个包含选择然后包含两个元素的序列。
xcut

1
@ Daij-Djan我也发现它没有用。尝试在选择元素上添加maxOccurs =“ unbounded”,以便允许多个子元素。
MikeD

107

在以后的编辑中添加的问题的替代表达形式似乎仍未得到解答:如何指定元素的子元素中必须有一个命名为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)

为了允许“ 1”或“ 2”在给定位置出现多次,我们可以插入(1|2)*(或者[12]*如果我们的正则表达式语言接受该表示法)。在所有可用位置插入此表达式,我们得到

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

将其转换为内容模型非常简单。基本结构与regex等效(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已解除了对-group的某些限制,因此可以更简洁地定义此内容模型:

<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-group的这些更改实际上并不会改变语言的表达能力;它们只会使某些语言的定义更加简洁。


3
我喜欢XSD 1.0 xs:all替代品。
TWiStErRob

8
+1。这是一个很好的答案,值得更多的批评。
Christoffer Lette

1
好答案!我真的很喜欢这样的解释。它揭示了实现目标背后的所有逻辑和理由。现在,我不仅知道如何解决该问题,而且还学习了一种解决类似问题的新方法。使用有限状态自动化对此进行解释是一个很好的主意。
egelev 2014年

3
迈克尔,你说“这些对所有群体的改变实际上并不会改变语言的表达能力;它们只会使某些特定语言的定义更加简洁”。但是,如果将问题概括为任意数量的子元素,其中一个子元素可以出现一次,而另一个子元素可以出现任意次数,那么XSD 1.0解决方案将产生组合爆炸,不是吗?XSD 1.1解决方案将保持干净。
ebruchez 2014年

1
ebruchez,是- 表达能力,因为我用这个词,是不一样的简洁紧凑简洁,或可管理性。表达能力只问“这种形式主义可以定义这种语言吗?” 它不询问语法的大小,也不询问语法糖是否会使它更小。您提到的组合爆炸意味着在不将XSD 1.1更改为所有组的情况下处理大量元素变得非常不快(对于较大的n可能会耗尽内存)。这并不意味着它们原则上变得不可能。
CM Sperberg-McQueen

49

这终于对我有用:

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

5
的确,诀窍是使用xsd:choice和量词<xsd:choice minOccurs =“ 0” maxOccurs =“ unbounded”>
tivo

6
我认为值得指出的是,即使没有将序列元素封装在选择元素中,上述示例也可以工作。

9

但是据我了解,xs:choice仍然仅允许单个元素选择。因此,像这样将MaxOccurs设置为无界仅意味着“任何一个”子元素可以出现多次。这个准确吗?

xs:choice不会maxOccurs="unbounded"。由于,每次发生的“重复”都会单独进行选择。因此,您发布的代码是正确的,并且实际上将按照编写的内容进行操作。


您的评论以及@Alan提供的答案很好地解释了所有这些。
2012年

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>

这似乎符合您的问题。


minOccursmaxOccurs限制为1个xs:all
帕维尔·米纳夫

Pavel:谢谢。。。我
仔细

1

如果以上方法均无效,则可能是您正在进行EDI事务处理,因此您需要针对HIPPA架构或任何其他复杂xsd验证结果。要求是,说有8个REF段,并且它们中的任何一个都必须以任何顺序出现,并且也不是全部都必需,这意味着要说您可以按照以下顺序来使用它们:第1 REF,第3 REF,第2 REF,第9 REF。在默认情况下,EDI接收将失败,因为默认的复杂类型为

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

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

<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本身中查找剩余的值。添加触发器将使它们全部都是唯一的,并且它们将在任何顺序和情况下通过(例如使用9中的5,而不是全部9/9)。

希望对您有帮助,因为我在此上花费了将近20个小时。

祝好运

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.