为相同的根元素创建2种不同的类型

时间:2012-08-16 14:36:41

标签: xml xsd jaxb

我想为2个不同的xml创建一个模式文件(我可以将其拆分为2个模式,但由于根元素相同,我希望将其保存在一个文件中)。

现在我有两种不同的XML。

<orderStatus shipStatus="SHIPPED/PENDING">
    <orderId>1234</orderId>
    <orderedBy>userName</orderedBy>
    <orderedOn>2012-07-23T11:35:51.000-04:00</orderedOn>
</orderStatus>

,第二个XML是

<orderStatus modifyShipStatus="SUSPENDED/PENDING">
    <shipStatus>101</shipStatus>
</orderStatus>

我怎么能为这2个xml提供1 xsd?当我尝试使用一个1类型创建根元素时,它工作正常但是当我尝试添加另一个类型时,JAXB抛出错误,该元素已经定义。这使得感觉。

1 个答案:

答案 0 :(得分:2)

答案部分取决于您想要说什么,部分取决于您使用的模式语言:DTD? XSD 1.0? XSD 1.1? RelaxNG?其他......?哦,是的,我看到问题标记为XSD,所以我假设您正在寻找XSD解决方案。

如果您想说orderStatus元素可以 序列orderIdorderedByorderedOn 序列shipStatus作为子级,并且属性shipStatusmodifyShipStatus是可选的,然后在内容模型中这样说是直截了当的。

在DTD表示法中(我在这里使用它的紧凑性)你会写:

<!ELEMENT orderStatus ((orderId, orderedBy, orderedOn) | shipStatus) >
<!ATTLIST orderStatus
          shipStatus CDATA #IMPLIED
          modifyShipStatus CDATA #IMPLIED
>

或者在XSD表示法中,写下

<xs:element name="orderStatus" type="my:orderStatus"/>  
<xs:complexType name="orderStatus">
  <xs:choice>
    <xs:sequence>
      <xs:element ref="my:orderId"/>
      <xs:element ref="my:orderedBy"/>
      <xs:element ref="my:orderedOn"/>
    </xs:sequence>
    <xs:element ref="my:shipStatus"/>
  </xs:choice>
  <xs:attribute name="shipStatus"/>
  <xs:attribute name="modifyShipStatus"/>
</xs:complexType>

然后你就完成了。

如果您只想要允许两个属性中的一个,或者您希望合法子项依赖于是否存在一个或另一个属性,则事情会更复杂。 (有些文档设计人员会说,如果你想要的话,你有两个非常不同的元素类型,你坚持使用相同的名称进行调用,这使得验证变得非常困难。)

在这种情况下,您的选择是:

  • 如上所述使用DTD和/或XSD 1.0架构,并在文档中或使用Schematron或其他方法表达其他约束。

  • 使用XSD 1.1,如上所述定义内容模型和属性,并添加断言以表示

    • 必须出现其中一个属性shipStatusmodifyShipStatus
    • 当且仅当名为shipStatus的孩子出现时,必须显示属性orderId
    • 当且仅当名为modifyShipStatus的孩子出现时,必须显示属性shipStatus
  • 使用XSD 1.1,为两种形式的orderStatus元素定义两种不同的类型,并使用条件类型赋值来说明适用的类型:

XSD看起来像这样:

   <xs:complexType name="orderStatus1">
      <xs:sequence>
        <xs:element ref="my:orderId"/>
        <xs:element ref="my:orderedBy"/>
        <xs:element ref="my:orderedOn"/>
      </xs:sequence>
      <xs:attribute name="shipStatus"/>
    </xs:complexType>  
    <xs:complexType name="orderStatus2">
      <xs:element ref="my:shipStatus"/>
      <xs:attribute name="modifyShipStatus"/>
    </xs:complexType>

    <xs:element name="orderStatus">
      <xs:alternative test="@shipStatus" type="my:orderStatus1"/> 
      <xs:alternative test="@modifyShipStatus" type="my:orderStatus2"/>
    </xs:element>
  • 我会顺便指出,它的爱好者经常引用Relax NG的能力来制定这种限制作为其优势之一。