明辉手游网中心:是一个免费提供流行视频软件教程、在线学习分享的学习平台!

XML Schema学习笔记

[摘要]1、复杂类型和简单类型之间最根本的区别就是:复杂类型的内容中可以包含其他元素,也可以带有属性(Attribute),但简单类型既不能包含子元素,也不能带有任何属性。 <xsd:complexType name="CNAddress" > <xsd:sequen...
1、复杂类型和简单类型之间最根本的区别就是:复杂类型的内容中可以包含其他元素,也可以带有属性(Attribute),但简单类型既不能包含子元素,也不能带有任何属性。
<xsd:complexType name="CNAddress" >
<xsd:sequence>
<xsd:element name="name"type="xsd:string"/>
<xsd:element name="street" type="xsd:string"/>
<xsd:element name="city"type="xsd:string"/>
<xsd:element name="zip"type="xsd:decimal"/>
</xsd:sequence>
<xsd:attribute name="country" type="xsd:NMTOKEN" fixed="US"/>
</xsd:complexType>

2、element存在约束:element可以通过其minOccurs和maxOccurs两个属性来约束元素实例存在的个数,这两个属性的缺省值都是1,表示默认情况下此元素在XML实例文档中必须出现一次。

3、attribute存在约束:元素属性也可以通过attribute的use属性来约束出现一次或根本不出现;use属性的取值可以是required,optional,prohibited三个值,缺省(默认)值是optional.

4、element和attribute都有一个default和fixed属性,针对element来书,只有当element实例为空时才采用此default值,而attribute是当实例不提供此attribute时才采用此default值,因此对attribute而言,只有其use值是optional时default值才有意义,而且对element和attribute来说fixed和default两个属性不能同时存在,否则会出现错误。

5、直接定义在schema元素下,即schema元素的顶级子元素的element和attribute都是全局的,称之为全局元素和全局属性,你在其他类型定义中可以直接引用。

6、派生新类型有两种方式:第一种就是直接从其他类型中扩展(继承)而来,另外一种就是通过对已有类型进行限定性约束而来。
如:以下有三种通过限定性约束定义的新类型:
通过值范围限定:
<xsd:simpleType name="myInteger">
<xsd:restriction base="xsd:integer">
<xsd:minInclusive value="10000"/>
<xsd:maxInclusive value="99999"/>
</xsd:restriction>
</xsd:simpleType>
使用模式匹配限定:
<xsd:simpleType name="SKU">
<xsd:restriction base="xsd:string">
<xsd:pattern value="\d{3}-[A-Z]{2}"/>
</xsd:restriction>
</xsd:simpleType>
使用枚举方式限定:
<xsd:simpleType name="CNCity">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="BeiJing"/>
<xsd:enumeration value="NanChang"/>
<xsd:enumeration value="ShangHai"/>
</xsd:restriction>
</xsd:simpleType>

7、原子类型(不可分割的类型,象string,integer等系统内建的类型)、列表类型、联合类型合起来统一称为简单类型。在Schema中有NMTOKENS、IDREFS、ENTITIES三种内建的列表类型,你也可以从已有的简单类型来创建list(列表)类型,但你不能从已有的list类型和复杂类型来创建列表(list)类型。
如:
<xsd:simpleType name="listOfMyIntType">
<xsd:list itemType="myInteger"/>
</xsd:simpleType>
在XML实例文档中列表类型的值是通过空格来进行分隔的,如果声明了一个listOfMyIntType元素,其值可能是:
<listOfMyInt>20003 15037 95977 95945</listOfMyInt>

8、有几个方面的元素可以应用于list类型来进行约束,它们是:length、minLength、maxLength和enumeration,如:
<xsd:simpleType name="USStateList">
<xsd:list itemType="USState"/>
</xsd:simpleType>
<xsd:simpleType name="SixUSStates">
<xsd:restriction base="USStateList">
<xsd:length value="6"/>
</xsd:restriction>
</xsd:simpleType>
注:针对列表类型要千万注意成员是string类型的,因为string类型中的空格和列表类型的分割符空格会造成部分混淆。
[page_break]9、对元素的定义可以采用通过指定其type属性为已定义的属性的方式,也可一采用匿名定义类型的方式,如:
采用类型定义:
<xsd:element name=”comment” type=”xsd:string”>
采用匿名定义:
<xsd:element name=”quantity”>
<xsd:simpleType>
<xsd:restriction base=”xsd:positiveInteger”>
<xsd:maxExclusive value=”100” />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>

10、union(联合)类型表示在XML实例文档中的元素实例符合union类型定义的成员类型中的一种就可以了(合法),这一点和C++中的联合类型有类似的概念,如:
<xsd:simpleType name="addrUnion">
<xsd:union memberTypes="xsd:string integer"/>
</xsd:simpleType>

11、复杂类型一般可以分为三类:第一类是包含字符内容和属性但不包含子元素;第二类是包含属性和子元素但不包含字符数据(字符数据包含在子元素中);第三类是即包含属性和字符内容又包含子元素的;那么如何来定义这三类类型呢?针对第一类可以通过simpleContent来实现,第二类可以通过complexContent来做到,第三类只需要将complexType的属性mixed设为true就可以了。具体的例子如下:

第一种类型(从一个简单类型扩展而来,增加了属性):
<xsd:element name="internationalPrice">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="xsd:decimal">
<xsd:attribute name="currency" type="xsd:string"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>

第二种类型(有一个element和两个attribute构成):
<xsd:element name="internationalPrice">
<xsd:complexType>
<xsd:complexContent>
<xsd:element name=”Country” ?type=”xsd:string” />
<xsd:attribute name="currency" type="xsd:string"/>
<xsd:attribute name="value"?type="xsd:decimal"/>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
注意:在这里由于默认情况下缺省是complexContent,所以在这里简略的写法是:
<xsd:element name="internationalPrice">
<xsd:complexType>
<xsd:element name=”Country”type=”xsd:string” />
<xsd:attribute name="currency" type="xsd:string"/>
<xsd:attribute name="value"?type="xsd:decimal"/>
</xsd:complexContent>
</xsd:element>

第三种类型:
<xsd:element name="letterBody">
<xsd:complexType mixed="true">
<xsd:sequence>
<xsd:element name="salutation">
<xsd:complexType mixed="true">
<xsd:sequence>
<xsd:element name="name" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="quantity"type="xsd:positiveInteger"/>
<xsd:element name="productName" type="xsd:string"/>
<xsd:element name="shipDate"type="xsd:date" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
第三种类型的实例可能如下:
<letterBody>
<salutation>Dear Mr.<name>Robert Smith</name>.</salutation>
Your order of <quantity>1</quantity> <productName>Baby
Monitor</productName> shipped from our warehouse on
<shipDate>1999-05-21</shipDate>
</letterBody>

12、根据11的描述那么要定义一个空内容的元素,也就是说定义一个只包含属性的元素,只要在complexContent中不包含任何子元素,就可以了,如:
<xsd:element name="internationalPrice">
<xsd:complexType>
<xsd:attribute name="currency" type="xsd:string"/>
<xsd:attribute name="value"type="xsd:decimal"/>
</xsd:complexType>
</xsd:element>

13、anyType是所有Schema类型的基类型,和Java中的Object类似。因此,以下定义:
<xsd:element name="anything" type="xsd:anyType"/>
可以写成:
<xsd:element name="anything"/>

14、Schema中用annotation、document、appInfo三个元素来进行注释,其中appI和document都是作为annotation的子元素来处理的。并且annotation一般是作为schema的顶层子元素、element的构造、类型定义的顶层子元素的。
如:
<xsd:element name="internationalPrice">
<xsd:annotation>
<xsd:documentation xml:lang="en">
element declared with anonymous type
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:annotation>
<xsd:documentation xml:lang="en">
empty anonymous type with 2 attributes
</xsd:documentation>
</xsd:annotation>
<xsd:complexContent>
<xsd:restriction base="xsd:anyType">
<xsd:attribute name="currency" type="xsd:string"/>
<xsd:attribute name="value"type="xsd:decimal"/>
</xsd:restriction>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>

15、choice仅允许在实例文档中使用其中一个子元素;在all中的所有元素都可以出现一次或一次都不出现,并且其中元素实例是没有顺序约束的,而且all必须放在任何内容模型的最顶层,为了说明这个问题,下面先列出一个合法的,然后列出一个不合法的以供对照说明:
<xsd:complexType name="PurchaseOrderType">
<xsd:all>
<xsd:element name="shipTo" type="USAddress"/>
<xsd:element name="billTo" type="USAddress"/>
<xsd:element ref="comment" minOccurs="0"/>
<xsd:element name="items"type="Items"/>
</xsd:all>
<xsd:attribute name="orderDate" type="xsd:date"/>
</xsd:complexType>
下面是一个不合法的:
<xsd:complexType name="PurchaseOrderType">
<xsd:sequence>
<xsd:all>
<xsd:element name="shipTo" type="USAddress"/>
<xsd:element name="billTo" type="USAddress"/>
<xsd:element name="items"type="Items"/>
</xsd:all>
<xsd:sequence>
<xsd:element ref="comment" />
</xsd:sequence>
</xsd:sequence>
<xsd:attribute name="orderDate" type="xsd:date"/>
</xsd:complexType>
[page_break]16、在存在很多类型中都有几个相同的类型的情况,可以采用属性组的方式来进行重用,属性组定义的格式是:
<xsd:attributeGroup name=”attrGroupName”>
<xsd:attribute name=”attrName1” type=”xsd:string” />
<xsd:attribute name=”attrName2” type=”xsd:string” />

</xsd:attributeGroup>
使用可以采用以下方式:
<xsd:element name=”testAttrGroup”>
<xsd:comlexType>
<xsd:element name=”element1”type=”xsd:string” />
<xsd:attributeGroup ref=”attrGroupName” />
</xsd:complexType>
</xsd:element>

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>