根据扩展的类型限制 XML 个元素

Restict XML elements based on the type they extend

我有以下 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>

如架构所示,我们有类型 "Car"、"MotorCycle" 和 "Wagon",它们都扩展了 "Vehicle" 类型。

我现在想在我的模式 (VehicleList) 中引入一个容器元素,它可以存储任何类型的元素,只要它扩展了 "Vehicle",这样我们就可以存储 [=26= 类型的元素]、"MororCycle" 或 "Wagon",但不是 "Cow" 类型的元素,因为它们会扩展 "Animal" 类型。

我已经搜索了很多,我认为不可能在 XML 模式中引入这种限制,基于 "ancestor" 类型,就像我们经常做的那样在 OO 编程中。

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

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

使用复杂类型和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

<?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元素是抽象的,它本身不能被使用(所以你必须使用on替换组成员)。