根据扩展的类型限制 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替换组成员)。
我有以下 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替换组成员)。