XML Schema学习笔记(二)
张小根
1、关于include的用法
include元素可以将外部的定义和声明引入到文档中,并且作为新Schema文档的一部分,但必须注意的一点是,被包含成员的目标命名空间必须和包含的目标命名空间一样。具体写法例子是:
<include schemaLocation=“http://www.example.com/schemas/address.xsd” />
2、如果一个类型是从另一个类型扩展而来的,那么定义为父类型的element,在实例文档中,可以通过符合子类型的element实例来代替,但必须通过xsi:type指明此元素的具体类型。例如:
<xsd:complexType name=”Person”>
<xsd:sequence>
<xsd:element name=”FirstName” type=”xsd:string” />
<xsd:element name=”LastName” type=”xsd:string” />
</xsd:sequence>
</xsd:complexType>
<!-- 扩展类型定义 -->
<xsd:complexType name=”Father”>
<complexContent>
<xsd:extension base=”Person”>
<xsd:sequence>
<xsd:element name=”gender”>
<xsd:restriction base=”string”>
<xsd:enumeration value=”male” />
</xsd:restriction>
</xsd:element>
</xsd:sequence>
</xsd:extension>
</complexContent>
</xsd:complexType>
<!-- 类型的声明 -->
<xsd:element name=”human” type=”Person” />
在XML实例文档中针对human可以是这样的(和面向对象有类似的概念):
<human xsi:type=”Father”>
<name>xiaogen</name>
<gender>male</gender>
</human>
3、关于置换组
XML Schema提供了一种机制叫置换组,允许原先定义好的元素被其他元素所替换。更明确的,这个置换组包含了一系列的元素,这个置换组中的每一个元素都被定义为可以替换一个指定的元素,这个指定的元素称为头元素(Head Element),需要注意的是头元素必须作为全局元素声明,注意,当一个实例文档包含置换元素时替换元素的类型时从它们的头元素那里派生的,此时并不需要使用我们前面所说的xsi:type来识别这些被派生的类型,当定义了置换组之后,并非意味着不能使用头元素,而只能使用这个置换组中的元素,它只是提供了一个允许元素可替换使用的机制。例如:
<xsd:schema>
<xsd:element name=”comment” type=”xsd:string”/>
<xsd:element name=”shipComment” type=”xsd:string”
substitutionGroup=”comment” />
<xsd:element name=”customerComment type=”xsd:string”
substituionGroup=”comment” />
<xsd:element name=”order”>
<xsd:complexType>
<xsd:element name=”productName” type=”xsd:string” />
<xsd:element name=”price” type=”xsd:decimal” />
<xsd:element ref=”comment” />
<xsd:element name=”shipDate” type=”xsd:date” />
</xsd:complexType>
</xsd:element>
</xsd:schema>
下面是实例文档的一个例子:
<order>
<productName>Lapis necklace</productName>
<price>999</price>
<shipComment>Use gold wrap if possible</shipComment>
<customerComment>Want this for the holidays!</customerComment>
<shipDate>2004-08-15</shipDate>
</order>
4、抽象元素和抽象类型
当一个元素或者类型被声明为“abstract”时,那么它就不能在实例文档中使用。当一个元素被声明为”abstract”的时候,元素的置换组的成员必须出现在实例文档中。当一个元素相应的类型被定义声明为"abstract"时,所有关联该元素的实例必须使用"xsi:type"来指明一个类型,这个类型必须是非抽象的,同时是在定义中声明的抽象类型的派生类型。
一、如将上面的comment元素的声明更改成:
<xsd:element name=”comment” type=”xsd:string” abstract=”true” />
那么上面的order实例中就只能包含customerComment和shipComment才是有效的。
二、如果有下面的类型定义:
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://cars.example.com/schema"
xmlns:target="http://cars.example.com/schema">
<complexType name="Vehicle" abstract="true"/>
<complexType name="Car">
<complexContent>
<extension base="target:Vehicle"/>
</complexContent>
</complexType>
<complexType name="Plane">
<complexContent>
<extension base="target:Vehicle"/>
</complexContent>
</complexType>
<element name="transport" type="target:Vehicle"/>
</schema>
根据以上的定义和声明,下面的实例片断就是不能通过验证的:
<transport xmlns="http://cars.example.com/schema" />
下面经过修改的就可以通过验证了。
<transport xmlns=“http://cars.example.com/schema”
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Car"/>
5、为了阻止类型被派生(包括通过限制派生和通过扩展派生),可以使用final来设置(有点和java中的final的概念类似),其值有三个:restriction,extension,#all。在模式文件的根元素schema元素中有一个可选的finalDefault属性,它的值能够取为final属性所允许的几个值之一。指定finalDefault属性的值的效果等于在模式文档中每个类型定义和元素声明中指定final属性,同时其值为finalDefault属性的值。如果想阻止前面的Person被限制派生,我们需要修改定义为如下:
<xsd:complexType name=”Person” final=”restriction”>
<xsd:sequence>
<xsd:element name=”FirstName” type=”xsd:string” />
<xsd:element name=”LastName” type=”xsd:string” />
</xsd:sequence>
</xsd:complexType>
6、因为在实例文档中与父类型关联的元素(也就是声明为父类型的元素)可以通过派生的子类型来替代,这在2中已经有详细的说明和例子。同时,XML Schema也提供了一种机制来控制派生类型以及置换组在实例文档中使用的机制。这种机制是通过类型的block属性来控制的,该属性可以取值为:restriction,extension,#all。和final属性一样,在模式文档的根元素schema元素里有一个可选的属性blockDefault,它的值为block属性所允许的值中的一个。指定blockDefault属性的作用等价于在模式文档中为每个类型定义和元素声明指定block属性。如在前面例子中我们想阻止在使用Father来替代Person的话我们需要修改Person的定义如下:
<xsd:complexType name=”Person” block=”extension”>
<xsd:sequence>
<xsd:element name=”FirstName” type=”xsd:string” />
<xsd:element name=”LastName” type=”xsd:string” />
</xsd:sequence>
</xsd:complexType>
取值为“extension”的block属性将阻止在实例文档中使用通过扩展的派生类型来替换Person(即可以阻止Father来替换Person),然而它不会阻止通过约束的派生来替换Person。
7、另外一种派生类型的控制机制是应用于简单类型方面的派生。当定义一个简单类型的时候,我们可以使用fixed属性对它的所有定义的参数进行修饰,以阻止这些参数在类型派生中被修改,例如:
<xsd:simpleType name=”Postcode”>
<xsd:restriction base=”xsd:string”>
< xsd:length value=”7” fixed=”true” />
</xsd:restriction>
</xsd:simpleType>
当这个简单类型被定义之后,我们能够派生出一个新的邮编类型,在其中我们使用了一个没有在基本类型中固定的参数:
<xsd:simpleType name="UKPostcode">
<xsd:restriction base=" Postcode">
<xsd:pattern value="[A-Z]{2}\d\s\d[A-Z]{2}"/>
</xsd:restriction>
</xsd:simpleType>
然而,我们不能购派生出一个这样的新的邮编类型:在其中我们重新定义了任何在基类型中已经被固定(fixed)的参数:
<xsd:simpleType name="UKPostcode">
<xsd:restriction base="ipo:Postcode">
<xsd:pattern value="[A-Z]{2}\d\d[A-Z]{2}"/>
<!-- illegal attempt to modify facet fixed in base type -->
<xsd:length value="6" fixed="true"/>
</xsd:restriction>
</xsd:simpleType>