带有多个可选子元素和常用必需元素的xsd

时间:2014-03-24 03:52:29

标签: xml xsd

我正在尝试为以下需要创建并提供给某些遗留代码的XML创建xsd。该产品已经出门了,我没有选择更改xml的定义。目标是保持兼容性创建单元测试,以确保架构符合传统期望。 (注意:我对创建xsd相当新,但过去曾经使用过很多)。

系统必须为其期望的错误条件创建以下简化结构之一:

<Customer>
    <CustomerNumber>A12</CustomerNumber>
    <ErrorText>Some kind of error description</ErrorText>
</Customer>

成功找到客户后,预计会:

<Customer>
    <CustomerNumber>A12</CustomerNumber>
    <Name>data</Name>
    <Address>data</Address>
    <City>data</City>    
</Customer>

我尝试了各种xsd方法,下面是我上次尝试使用组的方法。每次我基本上都以Multiple definition of element 'CustomerNumber' causes the content model to become ambiguous. A content model must be formed such that during validation of an element ...

结束

一种解决方案是将其分解为两个单独的xsd文件,并选择在单元测试验证中使用的相应文件,然后才能在顶级元素中使用可选元素?

<xs:group name="missinggroup">
    <xs:sequence>
       <xs:element name="CustomerNumber" type="xs:string" minOccurs="1" maxOccurs="1" />
       <xs:element name="ErrorText" type="xs:string" minOccurs="1" maxOccurs="1" />
    </xs:sequence>
</xs:group>

<xs:group name="foundgroup">
    <xs:sequence>
       <xs:element name="CustomerNumber" type="xs:string" minOccurs="1" maxOccurs="1" />
       <xs:element name="Name" type="xs:string" minOccurs="0" maxOccurs="1" />
       <xs:element name="Address" type="xs:string" minOccurs="0" maxOccurs="1" />
       <xs:element name="City" type="xs:string" minOccurs="0" maxOccurs="1" />
     </xs:sequence>
</xs:group>

<xs:element name="Customer">
    <xs:complexType>
      <xs:choice>
         <xs:group ref="missinggroup" />
         <xs:group ref="foundgroup" />
      </xs:choice>
    </xs:complexType>
</xs:element>

另一种已经尝试过的方法是:

<xs:element name="Customer">
    <xs:complexType>
      <xs:choice>
         <xs:element name="CustomerNumber" type="xs:string" minOccurs="1" maxOccurs="1" />
         <xs:group ref="missinggroup" />
         <xs:group ref="foundgroup" />
      </xs:choice>
    </xs:complexType>
</xs:element>

1 个答案:

答案 0 :(得分:4)

你几乎解决了这个问题。如果查看类型,可以查看问题的原因。这些都是模棱两可的,因为没有任何一个组可以让处理器通过查看第一个元素来查看哪条路径是正确的,因此错误。

现在,在两个选项中都需要<CustomerNumber>,以便可以从选项中删除。如果以这种方式查看,您可以将其视为<CustomerNumber>的序列,然后选择。这可以在XML Schema中构建为:

<xs:element name="Customer">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="CustomerNumber" type="xs:string"/>
        <xs:choice>
          <xs:element name="ErrorText" type="xs:string"/>
          <xs:sequence>
            <xs:element name="Name" type="xs:string"/>
            <xs:element name="Address" type="xs:string"/>
            <xs:element name="City" type="xs:string"/>
          </xs:sequence>
        </xs:choice>
      </xs:sequence>
  </xs:complexType>
</xs:element>

minOccursmaxOccurs的默认值均为1,因此为清楚起见,我已删除了这些内容。您也可能希望<Name><Address><City>出现一次,否则您只允许选择<CustomerNumber>,因此我也将其设置为1。

这是满足您要求的最简单的架构。在现实世界中,我可能会编写多个顶级定义并引用它们,因为它可以构建一个更易于维护的模式,但这对您来说可能不是问题。我更喜欢这样的东西:

<xs:element name="Customer">
  <xs:complexType>
    <xs:sequence>
      <xs:element ref="CustomerNumber"/>
        <xs:choice>
          <xs:element ref="ErrorText"/>
          <xs:group ref="AddressGroup"/>
        </xs:choice>
      </xs:sequence>
  </xs:complexType>
</xs:element>

<xs:element name="CustomerNumber" type="xs:string"/>    
<xs:element name="ErrorText" type="xs:string"/>
<xs:element name="Name" type="xs:string"/>
<xs:element name="Address" type="xs:string"/>   
<xs:element name="City" type="xs:string"/>

<xs:group name="AddressGroup">
    <xs:sequence>
        <xs:element ref="Name"/>
        <xs:element ref="Address"/>
        <xs:element ref="City"/>    
    </xs:sequence>
</xs:group>

它更可重用且更易于维护,但如果您正在使用遗留应用程序,则更改的可能性较小,您可以使用简单版本。