繁体   English   中英

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

[英]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 设置为无界应该只意味着“任何一个”子元素可以出现多次。 这是准确的吗?

如果上述解决方案不正确,我该如何实现上述要求?

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

  • 元素 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>

在稍后的编辑中添加的问题的替代表述似乎仍然没有答案:如何指定在一个元素的子元素中,必须有一个名为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 -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>

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

在您的问题中的架构中, child1child2可以按任意顺序出现任意次数。 所以这听起来像你在找什么。

如果您只希望其中一个出现无限次,则 unbounded 将不得不继续使用元素:

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

这最终对我有用:

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

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

不会。对于由于maxOccurs="unbounded"而发生的xs:choice的每次“重复”,选择都会单独发生。 因此,您发布的代码是正确的,并且实际上会按照您所写的那样做。

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

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

这似乎符合你的问题。

如果以上都不起作用,您可能正在处理 EDI 交易,您需要根据 HIPPA 模式或任何其他复杂的 xsd 验证您的结果。 要求是,假设有 8 个 REF 段,并且它们中的任何一个都必须以任何顺序出现,也不是全部都是必需的,这意味着您可以按照以下顺序 1st REF、3rd REF、2nd REF、9th 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>

解决方案:

这里简单地用“all”替换“sequence”或使用“choice”和最小/最大组合是行不通的!

首先将"xs:sequence" with "<xs:all>"现在,您需要在引用元素的位置进行一些更改,然后转到:

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

***现在在上面的段中添加触发点,像这样 trigger_field="REF01_...complete name.." 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 个小时在这上面。

祝你好运

如果您的子元素很少,那么您可以在 <xs:choice> 中列出所有可能的序列。 这为每个序列提供了您想要的灵活性。 作为N! 增长非常迅速,这只适合最多 4 个子元素。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM