XSD - how to allow elements in any order any number of times?

我正在尝试创建一个 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 设置为无界应该只意味着“任何一个”子元素可以出现多次。准确吗?

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

编辑 : 如果需求如下呢?

  • 元素 child 1 child 2可以显示任何 次数(0到无界)
  • 元素按任意顺序排列
  • 元素 child 3和 child 4应该只出现一次。

比如说, this xml is valid:

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

but this is not (missing child3)

<foo>
<child1> value </child1>
<child1> value </child1>
<child2> value </child2>
<child4> value </child4>
<child1> value </child1>
</foo>
121698 次浏览

在您的问题中的模式中,child1child2可以以任何顺序、任何次数出现。这听起来就是你要找的东西。

如果你只想让它们中的一个无限次出现,那么无界元素就只能出现在元素上:

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

您应该会发现下面的模式允许您所提议的内容。

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

这似乎符合你的问题。

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

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

这就是最终对我奏效的方法:

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

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

这是一种直接定义的正则语言,您需要的内容模型与定义字符串集的正则表达式同构,其中数字“3”和“4”只出现一次,数字“1”和“2”出现多次。如果不清楚如何编写这个代码,那么可以考虑构建什么样的有限状态机来识别这种语言。它将至少有四种不同的状态:

  • 没有看到“3”或“4”的初始状态
  • 一个居间态,其中的’3’已经看到,但不是’4’
  • 这个居间态中只有’4’出现,而没有’3’
  • “3”和“4”都出现过的最后一种状态

无论自动机处于什么状态,都可以读取“1”和“2”; 它们不会改变机器的状态。在初始状态中,“3”或“4”也将被接受; 在中间状态中,只接受“4”或“3”; 在最终状态中,既不接受“3”也不接受“4”。如果我们首先为语言的子集定义一个 regex,其中只出现“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组的改变实际上并没有改变语言的表达能力; 它们只是使某些类型的语言的定义更加简洁。

如果上面的方法都不起作用,那么您可能正在处理 EDI 事务,需要根据 HIPPA 模式或任何其他复杂的 xsd 验证结果。 要求是,假设有8个 REF 片段,它们中的任何一个都必须以任何顺序出现,而且不是全部都是必需的,意思是说你可以按照第一个 REF,第三个 REF,第二个 REF,第九个 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">

***Now in the above segment add trigger point in the end like this trigger_field="REF01_...complete name.." trigger_value = "38" 对于触发值不同的其他 REF 片段也一样,比如说“18”、“ XX”、“广州欢聚时代”等等。因此,您的记录信息现在看起来像: 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个小时在这上面。

祝你好运

如果子元素非常少,那么可以在 < xs: choice > 中列出所有可能的序列。这使得每个序列具有所需的灵活性。作为 N!正在迅速增长,这只适合约4个子元素。