XSD指XML Schema Definition ,这是一篇XSD的笔记。

概述

schema的大体作用与DTD相同,但比起DTD,schema更为完备。能够进行对元素更细致地约束,能够实现面向对象的特征,以及拥有良好的扩展性。最主要的是:schema的文档结构利用了XML的基本语法规则,继承了XML的自描述性与可读性。

schema文档的扩展名为 .xsd

在XML文档中引用schema文档的基本框架为:

1
2
<根元素 xmlns:xsd="http://www.w3.org/2001/XMLSchema-instance" xsd:noNamespaceSchemaLocation="schema路径">
</根元素>

而在一个schema文档中,其基本框架为:

1
2
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
</xsd:schema>

语法

简单类型

在讲schema的基本结构之前,我们先聊一聊数据类型。与DTD不同,schema的所有数据都有其对应的数据类型。一般可以分为内置数据类型与派生数据类型,前者为系统自带,而后者则为我们手动编写的。

内置数据类型

以上这些便是系统自带的数据类型。看起来可能很繁多,但没关系,常用的只有string,integer,boolean等。大概了解一下就行,反正用到了可以现场查。使用内置数据类型的基本框架为:

1
type="xsd:类型名"

派生数据类型

自带的数据类型肯定不够用,这时就需要我们自己定义数据类型。定义数据类型的基本框架为:

1
2
3
<xsd:simpleType name="类名"> 
内容
</xsd:simpleType>

“内容”部分可以是限制列表 或者组合 。可能看起来有点乱,我们接下来一一介绍:

限制
1
2
3
4
5
<xsd:simpleType name="类名"> 
<xsd:restriction base="基类型">
限制内容
</xsd:restriction>
</xsd:simpleType>

基类型即为当前类型的父类型,一般为string或integer。而restriction即为对当前类型的数据添加限制条件,限制条件有以下几种:

限定 描述
enumeration 定义可接受值的一个列表
fractionDigits 定义所允许的最大的小数位数。必须大于等于0。
length 定义所允许的字符或者列表项目的精确数目。必须大于或等于0。
maxExclusive 定义数值的上限。所允许的值必须小于此值。
maxInclusive 定义数值的上限。所允许的值必须小于或等于此值。
maxLength 定义所允许的字符或者列表项目的最大数目。必须大于或等于0。
minExclusive 定义数值的下限。所允许的值必需大于此值。
minInclusive 定义数值的下限。所允许的值必需大于或等于此值。
minLength 定义所允许的字符或者列表项目的最小数目。必须大于或等于0。
pattern 定义可接受的字符的正则表达序列。
totalDigits 定义所允许的阿拉伯数字的精确位数。必须大于0。
whiteSpace 定义空白字符(换行、回车、空格以及制表符)的处理方式。

举个例子:

1
2
3
4
5
<xsd:simpleType> 
<xsd:restriction base="xsd:string">
<xsd:pattern value="[a-z]"/>
</xsd:restriction>
</xsd:simpleType>

所能接受的数据就是一串仅有小写字母构成的字符串。

1
2
3
4
5
6
7
<xsd:simpleType> 
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Audi"/>
<xsd:enumeration value="Golf"/>
<xsd:enumeration value="BMW"/>
</xsd:restriction>
</xsd:simpleType>

所能接受的字符串数据需要从"Audi","Golf"与"BMW"三个中选择。

列表

通过列表进行派生,实际上就是在定义列表中每个数据的具体类型的基础上,允许多个数据构成一个列表(其中使用空格进行分隔)。 举两个例子就能明白了:

1
2
3
4
5
6
<xsd:simpleType name="valuelist">
<xs:list itemType="xs:integer"/>
</xsd:simpleType>
<xsd:element name="intvalues" type="valuelist"/>
<!-- 所对应的元素为 -->
<intvalues>100 34 56 -23 1567</intvalues>
1
2
3
4
5
6
<xsd:simpleType name="valuelist">
<xsd:list itemType="xs:string"/>
</xsd:simpleType>
<xsd:element name="stringvalues" type="valuelist"/>
<!-- 所对应的元素为 -->
<stringvalues>I love XML Schema</stringvalues>
组合

列表可以处理多个同类型的元素,而遇到多个不同类型的元素,则需要使用union:

1
2
3
<xsd:simpleType name="integerOrDate">
<xsd:union memberTypes="xsd:integer xsd:date"/>
</xsd:simpleType>

XML Schema规范中对simpleType语法的描述

1
2
3
4
5
6
<simpleType
final = (#all | List of (list | union | restriction))
id = ID
name = NCName>
Content: (annotation?, (restriction | list | union))
</simpleType>

final属性的值表示该数据类型不允许进行的操作列表,#all 表示不能对该类型进行任何操作。

简单元素

schema中定义简单元素的基本框架为:

1
<xsd:element name="元素名" type="数据类型"/>

举个例子:

1
2
3
<xsd:element name="color" type="xs:string"/>
<!-- 所对应的元素为 -->
<color>blue</color>

同时,我们可以为元素添加默认值或固定值

1
2
3
4
<!-- 若没规定值,则默认为red -->
<xsd:element name="color" type="xs:string" default="red"/>
<!-- 其取值只能为red -->
<xsd:element name="color" type="xs:string" fixed="red"/>

复合元素

与简单元素对应,复合元素即为包含其他元素或属性的元素,其基本框架为:

1
2
3
4
<xsd:element name="元素名">
<xsd:complexType>
</xsd:complexType>
</xsd:element>

若要向其中添加属性,则可以用<xsd:attribute>元素:

1
2
3
4
5
<xsd:element name="元素名">
<xsd:complexType name="元素名">
<xsd:attribute name="属性名" type="数据类型" use="可用性"/>
</xsd:complexType>
</xsd:element>

use = (optional | prohibited | required) 可以表示所定义的属性为可选、禁止出现或必须出现。

同样,属性中也可以添加default或fixed属性。

而若要向其中添加元素,由于元素是有序 的,所以需要被放在一个序列 当中,其基本框架为:

1
2
3
4
5
6
7
8
9
<xsd:element name="元素名">
<xsd:complexType name="元素名">
<xsd:sequence>
<xsd:element name="元素名" type="数据类型"/>
</xsd:sequence>
<!-- 当然也可以继续添加属性 -->
<xsd:attribute/>
</xsd:complexType>
</xsd:element>

容器

不止序列,在复合数据类型中我们还可以选用选择容器(xsd:choice)或无序容器(xsd:all)。这两个容器的功能就如其名,举两个例子就能明白:

1
2
3
4
5
6
7
8
9
10
11
12
13
<xsd:element name="元素名">
<xsd:complexType>
<xsd:sequence>
<xsd:choice>
<xsd:sequence>
<xsd:element name="shipTo" type="USAddress"/>
<xsd:element name="billTo" type="USAddress"/>
</xsd:sequence>
<xsd:element name="singleUSAddress" type="USAddress"/>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
1
2
3
4
5
6
7
8
<xsd:element name="元素名">
<xsd:complexType>
<xsd:all>
<xsd:element name="firstname" type="xsd:string"/>
<xsd:element name="lastname" type="xsd:string"/>
</xsd:all>
</xsd:complexType>
</xsd:element>

maxOccurs 和 minOccurs 属性

这两个属性用于限制元素的最大和最小出现次数,如果允许一个元素出现无数次,那么可以让maxOccurs=“unbounded”。举个例子:

1
<xsd:element name="author" type="xsd:string" minOccurs="1" maxOccurs="3"/>

ref 属性

ref 属性表示引用某个已经定义的全局元素,举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<xsd:element name="person">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="firstname" type="xsd:string"/>
<xsd:element name="lastname" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<!-- 以上为person元素定义 -->
<xsd:element name="employee">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="ID" type="xsd:string"/>
<!-- 引用person -->
<xsd:element ref="person"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>

nillable 属性和 xsi:nil 属性

nillable=false 表示不允许某个元素的值为空;nillable=true 表示允许某个元素的值为空。如:

1
<xsd:element name="studentid" type="xsd:integer" nillable="true"/>

如果在对应的XML文档中出现:

1
<studentid></studentid>

就会出现错误,其会被解析器识别成空字符串""。所以在XML文档中应该使用xsi命名空间的nil属性,使得该元素的文本内容真正为空:

1
<studentid xsi:nil="true"></studentid>

替换组

替换组其实就是允许用其他元素来替换已定义过 的元素,相当于给一个元素起个别名:

1
2
<xsd:element name="name" type="xs:string"/>
<xsd:element name="姓名" substitutionGroup="name"/>

这样一来,在XML文档中的以下两种元素都是正确的:

1
2
<name>Lin</name>
<姓名>Lyx</姓名>

约束

类似于关系数据库,XML有几种约束方式可以约束元素的使用:

unique约束

unique约束能够限定指定元素或属性的唯一性:

1
2
3
4
<xsd:unique name="约束名">
<xsd:selector xpath="选择路径"/>
<xsd:field xpath="元素/属性路径"/>
</xsd:unique>

这里的xpath部分后续会在xpath的章节里细讲,暂时只要知道是一个查询路径就可以了。举个例子:

1
2
3
4
<xsd:unique name="bookUnique">
<xsd:selector xpath="Book"/>
<xsd:field xpath="."/>
</xsd:unique>

这里就限定了Book元素的唯一值,如果在XML这样写便会报错:

1
2
<Book>myBook</Book>
<Book>anotherBook</Book>

field选择器同时也可以用来选择某一属性,如:

1
<xsd:field xpath="@id"/>
Key约束

Key约束可以使得某一属性或元素的值必须从Key集合中选择,而Keyref则可以限定另一个元素或属性的值必须在这个集合中:

1
2
3
4
5
6
7
8
<xsd:key name="key名">
<xsd:selector xpath="选择路径"/>
<xsd:field xpath="元素/属性路径"/>
</xsd:key>
<xsd:keyref refer="关联key" name="keyref名">
<xsd:selector xpath="选择路径"/>
<xsd:field xpath="元素/属性路径"/>
</xds:keyref>

来看一个例子就明白了:

1
2
3
4
5
6
7
8
<xsd:key name="sortKey">
<xsd:selector xpath="bookSort"/>
<xsd:field xpath="."/>
</xsd:key>
<xsd:keyref refer="sortKey" name="sortKeyRef">
<xsd:selector xpath="book"/>
<xsd:field xpath="@type"/>
</xsd:keyref>

所对应的XML文档:

1
2
3
4
5
6
7
8
<bookSort>technology</bookSort>
<bookSort>novel</bookSort>
<book type="technology">
<name>XML Schema应用</name>
</book>
<book type="novel">
<name>疯狂程序员</name>
</book>

名为“sortKey”的key约束从所有 bookSort元素中读取了值。同时名为“sortKeyRef”的keyref针对所有book元素的type属性进行匹配,若其值来源于key约束,则合法,否则会报错。

元素/属性组

元素组类似于一个数组,可以将多个元素装进这个组中,方便多次调用,举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<xs:group name="custGroup">
<xs:sequence>
<xs:element name="customer" type="xs:string"/>
<xs:element name="orderdetails" type="xs:string"/>
<xs:element name="billto" type="xs:string"/>
<xs:element name="shipto" type="xs:string"/>
</xs:sequence>
</xs:group>

<xs:complexType name="ordertype">
<!-- 调用元素组 -->
<xs:group ref="custGroup"/>
<xs:attribute name="status" type="xs:string"/>
</xs:complexType>

同理,也可以使用属性组:

1
2
<xsd:attributeGroup name="属性组名">
</xsd:attributeGroup>

任意元素/属性

为 XML 文档编写 Schema 模式时,可能有些部分无法确定、或者允许用户在某个位置添加任何所需的内容(Schema 文档中的任何全局元素),则可以使用any元素:

1
<xsd:any/>

同理,有any属性:

1
<xsd:anyAttribute/>

复合类型

与简单类型相同,我们也可以将一个复合类型复用。定义一个复合类型的基本框架为:

1
2
3
<xsd:complexType name="类型名">
类型内容
</xsd:complexType>

这样一来,在定义复合元素的时候就可以不再每次都写这一大串复合类型内容了,可以直接调用:

1
<xsd:element name="元素名" type="类型名"/>

而对于只包含文本和属性 的复合元素类型,schema中引入了一个名为simpleContent的元素:

1
2
3
4
5
6
7
<xsd:complexType name="类型名">
<xsd:simpleContent>
<xsd:extension base="xsd:integer">
<xsd:attribute name="country" type="xsd:string"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>

以下内容可能比较难懂, 没事,我自己也没看懂。 稍作了解即可

这里的xsd:extension也可以用xsd:restriction代替,其差别为:

  • xsd:extension 元素:

    可以对基础类型进行扩展;但元素文本内容的类型实际上只能由 base 属性所指定的类型来决定,在 xsd:extension 元素中,只能定义与属性有关 的内容。

  • xsd:restriction 元素:

    可对基础类型进行限制;与 xsd:extension 一样,元素文本的类型是由 base 属性所指定的类型来决定,但是可以在 xsd:restriction 元素中使用各种限制方面对其进行限制; 注意:base属性必须是“属性+文本”。

同样,与之对应:也可以使用complexContent 元素。可以自行了解,这里不多赘述。

XML Schema规范中对complexType语法的描述

1
2
3
4
5
6
7
8
9
10
11
<complexType
abstract = boolean : false
block = (#all | List of (extension | restriction))
final = (#all | List of (extension | restriction))
id = ID
mixed = boolean : false
name = NCName>
Content: (annotation?, (simpleContent | complexContent |
((group | all | choice | sequence)?,
((attribute | attributeGroup)*, anyAttribute?))))
</complexType>

abstract 属性表示该复杂类型是一个抽象类,只能用作其他类型的父类型,但不能实例化。

如果不希望使用多态性,可以使用 complexType 的 block 属性(它的取值可能为 #all、extension、restriction)。extension 和 restriction,分别表示禁止使用任何通过扩展/限制而派生的子类型的实例来代替声明为父类的元素。block 和 final 属性是有区别的,因为即使 block=“#all”,仍然可以派生新的子类型,而 final=“#all” 则表示禁止派生。对于 block 来说,#all 表示禁止使用任何子类型的实例来代替声明为父类的元素。

导入

我们也可以在一个schema文档中导入另一个schema文档,只需要运用include或import元素。

使用xsd:include 导入目标命名空间相同的Schema:

1
<xsd:include schemaLocation="另外一个schema.xsd"/>

使用xsd:import 导入目标命名空间不同的Schema:

1
<xsd:import namespace="另一个命名空间" schemaLocation="另外一个schema.xsd"/>

使用xsd:include 导入没有命名空间的Schema:

1
<xsd:include schemaLocation="另外一个schema.xsd"/>

如果本schema指定了目标命名空间,这时将发生变色龙效果 ,所有在另一个schema中的元素,类型和属性都将使用本schema定义的目标命名空间。