根据XML元素的扩展类型重构XML元素

时间:2017-09-20 08:22:49

标签: xml xsd containers restriction ancestor

我有以下xsd架构:

<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:complexType name="Vehicle">
  <xs:sequence>
    <xs:element name="numberOfWheels" type="xs:int" minOccurs="0" maxOccurs="1"/>
  </xs:sequence>
</xs:complexType>

<xs:element name="car" type="Car"/>
<xs:complexType name="Car">
  <xs:complexContent>
    <xs:extension base="Vehicle">
      <xs:sequence>
        <xs:element name="numberOfSeats" type="xs:int" minOccurs="0" maxOccurs="1"/>
      </xs:sequence>
    </xs:extension>
  </xs:complexContent>
</xs:complexType>

<xs:element name="motorCycle" type="MotorCycle"/>
<xs:complexType name="MotorCycle">
  <xs:complexContent>
    <xs:extension base="Vehicle">
      <xs:sequence>
        <xs:element name="hasLuggageCompartment" type="xs:boolean" minOccurs="0" maxOccurs="1"/>
      </xs:sequence>
    </xs:extension>
  </xs:complexContent>
</xs:complexType>

<xs:element name="wagon" type="Wagon"/>
<xs:complexType name="Wagon">
  <xs:complexContent>
    <xs:extension base="Vehicle">
      <xs:sequence>
        <xs:element name="typeOfCargo" type="xs:string" minOccurs="0" maxOccurs="1"/>
      </xs:sequence>
    </xs:extension>
  </xs:complexContent>
</xs:complexType>

<xs:element name="vehicleList" type="VehicleList"/>
<xs:complexType name="VehicleList">
  <xs:sequence>
    <xs:element <!-- what to do here? --> minOccurs="1" maxOccurs="unbounded"/>
  </xs:sequence>
</xs:complexType>

</xs:schema>

如图所示,我们有类型&#34; Car&#34;,&#34; MotorCycle&#34;和&#34; Wagon&#34;,所有这些都扩展了&#34; Vehicle&#34;类型。

我现在想在我的模式(VehicleList)中引入一个容器元素,它允许存储任何类型的元素,只要它扩展&#34; Vehicle&#34;,以便我们可以存储类型&#34的元素; Car&#34;,&#34; MororCycle&#34;或者&#34; Wagon&#34;,但不是,例如,&#34; Cow&#34;因为他们会扩展动物&#34;类型。

我已经搜索了很多,我认为不可能在XML模式中引入这种限制,基于&#34;祖先&#34;类型,就像我们在OO编程中经常习惯的那样。

所以我的问题:是否可以声明一个容器元素,根据它们扩展的类型限制它包含的元素,如果是的话,怎么做?

提前感谢您的回答和建议。

1 个答案:

答案 0 :(得分:1)

使用ComplexTypes和xsi:type

最简单,最易扩展的方法是将类型设置为Vehicle。

<xs:complexType name="VehicleList">
    <xs:sequence>
        <xs:element name="VehicleElm"
                       type="Vehicle"
                       minOccurs="1"
                       maxOccurs="unbounded" />
    </xs:sequence>
</xs:complexType>

然而,生成的XML看起来像这样,可能不完全是你想要的(添加了xsi:type属性)

<?xml version="1.0" encoding="utf-8"?>
<!-- Created with Liquid Studio 2018 - Developer Bundle 16.0.0.0 (https://www.liquid-technologies.com) -->
<vehicleList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                 xsi:noNamespaceSchemaLocation="XSDFile.xsd">
    <VehicleElm xsi:type="Car">
        <numberOfWheels>4</numberOfWheels>
        <numberOfSeats>2</numberOfSeats>
    </VehicleElm>
    <VehicleElm xsi:type="Wagon">
        <numberOfWheels>6</numberOfWheels>
        <typeOfCargo>stuff</typeOfCargo>
    </VehicleElm>
</vehicleList>

使用替换组

另一种方法是使用替换组,它在XSD中稍微复杂一些,但提供更清晰的XML

enter image description here

<?xml version="1.0" encoding="utf-8" ?>
<!--Created with Liquid Studio 2018 - Developer Bundle 16.0.0.0 (https://www.liquid-technologies.com)-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:complexType name="VehicleType">
        <xs:sequence>
            <xs:element name="numberOfWheels"
                           type="xs:int"
                           minOccurs="0"
                           maxOccurs="1" />
        </xs:sequence>
    </xs:complexType>
    <xs:element name="Vehicle"
                   type="VehicleType"
                   abstract="true" />
    <xs:element name="car"
                   substitutionGroup="Vehicle">
        <xs:complexType>
            <xs:complexContent>
                <xs:extension base="VehicleType">
                    <xs:sequence>
                        <xs:element name="numberOfSeats"
                                       type="xs:int"
                                       minOccurs="0"
                                       maxOccurs="1" />
                    </xs:sequence>
                </xs:extension>
            </xs:complexContent>
        </xs:complexType>
    </xs:element>
    <xs:element name="motorCycle"
                   substitutionGroup="Vehicle">
        <xs:complexType>
            <xs:complexContent>
                <xs:extension base="VehicleType">
                    <xs:sequence>
                        <xs:element name="hasLuggageCompartment"
                                       type="xs:boolean"
                                       minOccurs="0"
                                       maxOccurs="1" />
                    </xs:sequence>
                </xs:extension>
            </xs:complexContent>
        </xs:complexType>
    </xs:element>
    <xs:element name="wagon"
                   substitutionGroup="Vehicle">
        <xs:complexType>
            <xs:complexContent>
                <xs:extension base="VehicleType">
                    <xs:sequence>
                        <xs:element name="typeOfCargo"
                                       type="xs:string"
                                       minOccurs="0"
                                       maxOccurs="1" />
                    </xs:sequence>
                </xs:extension>
            </xs:complexContent>
        </xs:complexType>
    </xs:element>
    <xs:element name="vehicleList"
                   type="VehicleList" />
    <xs:complexType name="VehicleList">
        <xs:sequence>
            <xs:element ref="Vehicle"
                           minOccurs="1"
                           maxOccurs="unbounded" />
        </xs:sequence>
    </xs:complexType>
</xs:schema>

生成的XML看起来像这样

<?xml version="1.0" encoding="utf-8"?>
<!-- Created with Liquid Studio 2018 - Developer Bundle 16.0.0.0 (https://www.liquid-technologies.com) -->
<vehicleList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
                 xsi:noNamespaceSchemaLocation="XSDFile2.xsd">
    <car>
        <numberOfWheels>4</numberOfWheels>
        <numberOfSeats>2</numberOfSeats>
    </car>
    <motorCycle>
        <numberOfWheels>2</numberOfWheels>
        <hasLuggageCompartment>false</hasLuggageCompartment>
   </motorCycle>
</vehicleList>

基本上你可以使用元素Vehicle,任何替换组成员都可以在它的位置使用,并且因为Vehicle元素是抽象的,所以它不能自己使用(所以你必须使用它取代组成员)。