XML详解:第二部分 XML Schema
XML Schema
模式指的是依照XML Schema规范,使用http://www.w3.org/2001/XMLSchema名称空间中的元素来描述XML文档结构的规则集。每个模式定义都是以一个根元素 xs:schema 开始,该元素属于 http://www.w3.org/2001/XMLSchema 名称空间。
模式用于定义XML文档结构,对XML进行约束,符合某个模式的XML文档称为实例。
声明是指括元素、属性的声明。
定义是指数据类型、元素组、属性组和一致性约束的定义。
不只是属性值有类型,元素也是有类型的。
元素如果包含子元素或者带有属性则称为复杂类型;如果元素仅仅包含字符数据,而不包含任何子元素,也不带有属性则为简单类型。属性总是只具有简单类型,因为属性不能有子元素或其他属性。
全局/局部声明/定义
直接在 xs:shema 元素下声明的元素、属性,它们可以通过xs:element和xs:attribute元素的ref属性来引用。
在全局声明中不能使用ref属性。全局声明的元素在实例文档中可以作为根元素出现。
另外,类型也可以定义成全局的。
模式与名称空间
目标名称空间
目标名称空间使用xs:schema元素的targetNamespace属性来指定:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"1
targetNamespace="http://www.sunxin.org/book" 2
xmlns:book="http://www.sunxin.org/book"> 3
<xs:element name="book" type="book:bookType"/> 4
<xs:complexType name="bookType"> 5
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="author" type="xs:string"/>
</xs:sequence>
<xs:attribute name="isbn" type="xs:token"/>
</xs:complexType>
</xs:schema>
1、 所有在Schema模式文档里出现的用来定义模式规则的元素及内置类型都属性http://www.w3.org/2001/XMLSchema名称空间中元素。
2、 使用targetNamespace属性指定文档名称空间为http://www.sunxin.org/book,即表示在该模式文档中声明的元素、定义的类型都属于都属性于这个目标空间了。
3、 声明名称空间http://www.sunxin.org/book,并为该名称空间绑定前缀book,使用该前缀来引用http://www.sunxin.org/book名称空间中的类型bookType。
4、 文档中定义的类型都属于文档名称空间,因此在引用类型时,需要加上book前缀。
5、 在定义类型时,如果指定类型名,则不需要加上任何前缀,当使用targetNamespace属性后,在模式文档中定义的任何类型都属于目标名称空间。
带有xs前缀的元素和类型属于http://www.w3.org/2001/XMLSchema名称空间,而其他元素和类型则属于目标名称空间。注意,只有模式文档中的全局元素和全局属性才属于目标名称空间。上面的例子中,全局元素book属于目标名称空间,而局部元素title和author则不属于目标名称空间。
与上面模式对应的实例文档如下:
<?xml version="1.0" encoding="GB2312"?>
<book:book xmlns:book="http://www.sunxin.org/book" isbn="978-7-121-06812-6">
<title>《Struts 2深入详解》</title>
<author>孙鑫</author>
</book:book>
局部元素和属性的限定
在上面例子中,局部元素title和author没有被文档名称空间所限定,即不属于任何名称空间,如果要限定,可以通过 xs:schema 元素的elementFormDefault和attibuteFormDefault属性来设置。
限定局部元素:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.sunxin.org/book"
targetNamespace="http://www.sunxin.org/book"
elementFormDefault="qualified">
<xs:element name="book" type="bookType"/>
<xs:complexType name="bookType">
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="author" type="xs:string"/>
</xs:sequence>
<xs:attribute name="isbn" type="xs:token"/>
</xs:complexType>
</xs:schema>
elementFormDefault的默认值为“unqualified”,即对局部声明的元素不加限定。符合上面模式的实例文档如下:
<?xml version="1.0" encoding="GB2312"?>
<book:book xmlns:book="http://www.sunxin.org/book" isbn="978-7-121-06812-6">
<book:title>《Struts 2深入详解》</book:title>
<book:author>孙鑫</book:author>
</book:book>
如果属性被声明为全局属性或者xs:schema元素的attibuteFormDefault属性被设置成“qualified”的话,那么属性就必须在实例文档中将以带名称空间前缀方式出现。实际上,需要限定的属性必须明确加上名称空间前缀,因为XML名称空间推荐标准中并没有给出关于属性默认名称空间的机制,一个没有前缀的属性将不在任何的名称空间中。属性是附属于元素的,对于属性添加名称空间不是很有必要,因此在多数应用中都没有给属性添加限定。
下面是使用了attibuteFormDefault属性的模式文档:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.sunxin.org/book"
targetNamespace="http://www.sunxin.org/book"
elementFormDefault="qualified"
attributeFormDefault="qualified">
<xs:element name="book" type="bookType"/>
<xs:complexType name="bookType">
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="author" type="xs:string"/>
</xs:sequence>
<xs:attribute name="isbn" type="xs:token"/>
</xs:complexType>
</xs:schema>
attibuteFormDefault的默认属性值也是“unqualified”,符合上面的XML文档:
<?xml version="1.0" encoding="GB2312"?>
<book:book xmlns:book="http://www.sunxin.org/book" book:isbn="978-7-121-06812-6">
<book:title>《Struts 2深入详解》</book:title>
<book:author>孙鑫</book:author>
</book:book>
elementFormDefault和attibuteFormDefault属性除了在xs:schema 元素中设置外,还可以在xs:element和xs:attribute元素上分别使用form属性来限制局部元素与属性,不过这只能设置了元素或属性都起限定作用:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.sunxin.org/book"
targetNamespace="http://www.sunxin.org/book">
<xs:element name="book" type="bookType"/>
<xs:complexType name="bookType">
<xs:sequence>
<xs:element name="title" type="xs:string" form="qualified"/>
<xs:element name="author" type="xs:string" form="qualified"/>
</xs:sequence>
<xs:attribute name="isbn" type="xs:token" form="qualified"/>
</xs:complexType>
</xs:schema>
未声明目标名称空间
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="book" type="bookType"/>
<xs:complexType name="bookType">
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="author" type="xs:string"/>
</xs:sequence>
<xs:attribute name="isbn" type="xs:token"/>
</xs:complexType>
</xs:schema>
上面的bookType类型和声明的book元素都是没有名称空间限定的,所以在模式文档中引用类型或元素时,不需要添加任何的名称空间前缀。
如果对XMLSchema的元素和类型使用默认名称空间,那么对XMLSchema类型的引用也许不能和对用户自定义类型的引用相区分,从而导致模式文档错误:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema">
<element name="book" type="bookType"/>
<complexType name="bookType">
<sequence>
<element name="title" type="string"/>
<element name="author" type="string"/>
</sequence>
<attribute name="isbn" type="token"/>
</complexType>
</schema>
报错:'bookType' must refer to an existing simple or complex type.
这是因为验证器认为对bookType类型的引用是默认名称空间(http://www.w3.org/2001/XMLSchema)中定义的类型,而该名称空间中并没有这种类型,所以就报错了。
在XML实例文档中引用Schema模式文档
两个用于引用Schema模式文档的特殊属性:xsi:schemaLocation、xsi:noNamespaceSchemaLocation,前者用于声明了目标名称空间的模式文档,后者用于没有文档名称空间模式的文档,它们通常在实例文档中使用。
l xsi:schemaLocation
xsi:schemaLocation属性值由一对URI组成,使用空白符分开。第一个URI是名称空间的名字,即模式中的目标名称空间,第二个URI给出模式文档的位置,模式处理器将从这个位置读取模式文档。
<?xml version="1.0" encoding="GB2312"?>
<book xmlns="http://www.sunxin.org/book"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 1
xsi:schemaLocation="http://www.sunxin.org/book book.xsd"> 2
<title>《Struts 2深入详解》</title>
<author>孙鑫</author>
</book>
1、 声明XMLSchema实例名称空间(http://www.w3.org/2001/XMLSchema-instance),前缀一般为xsi,这样模式处理器就可以识别xsi:schemaLocation属性。
2、 使用xsi:schemaLocation属性指定名称空间http://www.sunxin.org/book和模式位置为book7.xsd相关。这里的book.xsd中声明的目标名称空间要求是http://www.sunxin.org/book。
xsi:schemaLocation属性的值可以由多个URI引用对组成:
<books xmlns="http://www.sunxin.org/bks" xmlns:p="http://www.sunxin.org/people"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sunxin.org/bks bks.xsd
http://www.sunxin.org/people people.xsd">
Schema推荐标准中指出,xsi:schemaLocation属性可以在实例中的任何元素上使用,而不一定是根元素,但必须出现在它要验证的任何元素和属性前面。
l xsi:noNamespaceSchemaLocation
用于引用没有目标空间的模式文档,它的值是单一的值,只用于指定模式文档的位置。
<?xml version="1.0" encoding="GB2312"?>
<book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="book.xsd"
isbn="978-7-121-06812-6">
<title>《Struts 2深入详解》</title>
<author>孙鑫</author>
</book>
注解
在Schema中可以使用“<!-- -->”,不过为了方便其他读者和应用程序来理解模式文档,Schema提供了三个元素来为模式提供注解。它们是xs:annotation、xs:documentation、xs:appinfo,其中xs:documentation和xs:appinfo是作为xs:annotation元素的子元素。xs:documentation元素用于旋转适合人阅读的信息,而xs:appinfo元素则用于工具、模式表和其他应用程序提供信息。
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:annotation>
<xs:documentation xml:lang="zh">
这是一份用于企业雇员信息描述的模式文档
</xs:documentation>
</xs:annotation>
</xs:schema>
xs:appinfo没有xml:lang属性。
简单类型
简单类型的元素只能包含字符数据,不能包含子元素,也不能包含属性。使用 xs:simpleType元素来定义。
XML Schema支持类型的派生,这和面向对象语言中对象的继承有些类似,但又不完全相同。XMLSchema类型的派生分为限制(xs:restriction)和扩展(xs:extension),通过限制派生的新类型的值范围是原类型值范围的子集,通过扩展可以为现有类型添加新的元素和属性。
对于简单类型,只有限制派生而没有扩展派生,我们只能通过限制一个现有的简单类型来派生一个新的简单类型。这些限制是通过http://www.w3.org/2001/XMLSchema名称空间中的一些元素(xs:restriction)来对派生类型进行约束的。
要定义新的简单类型,使用 xs:simpleType 元素,要对现有的基类型进行限制,使用xs:restriction元素。
自定义简单类型只能限制派生而不能扩展派生,通过限制派生得到的新的简单类型的值范围是其基类型值范围的子集。
内置简单类型
自定义简单类型
Schema中用来进行数据类型的约束元素,它们都有一个value属性:
范围:minInclusive(包含范围)、maxInclusive、minExclusive(不包含范围)、maxExclusive
长度:length、minLength、maxLength
精度:totalDigits、fractionDigits
枚举:enumeration
模式匹配:pattern
空白处理:whiteSpace
限制范围
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="score" type="scoreType"/>
<!--定义命名简单类型scoreType -->
<xs:simpleType name="scoreType">
<xs:restriction base="xs:integer">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="100"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="failedScore">
<!--在元素内部定义匿名简单类型 -->
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minExclusive value="0"/>
<xs:maxExclusive value="60"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>
限制长度
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="username">
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:minLength value="4"/>
<xs:maxLength value="8"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="password">
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:length value="8"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>
指定精度
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="check" type="checkType"/>
<xs:simpleType name="checkType">
<xs:restriction base="xs:decimal">
<xs:totalDigits value="11"/>
<xs:fractionDigits value="2"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
枚举值
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="municipality" type="municipalityType"/>
<xs:simpleType name="municipalityType">
<xs:restriction base="xs:token">
<xs:enumeration value="北京"/>
<xs:enumeration value="上海"/>
<xs:enumeration value="天津"/>
<xs:enumeration value="重庆"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
<municipality>天津</municipality>
注,取值只能是枚举值中的一个,不能是组合,如果想引用多个,则只能使用列表类型,请参考后面。
模式匹配
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="zipcode">
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:pattern value="\d{6}"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:schema>
空白处理
whiteSpace的有效值为:preserve、replace和collapse。
preserve:所有空白都被保留,数据类型xs:string的whiteSpace值就是preserve。
replace:值中出现的每一个制表符、换行、回车都用一个空格进行替换。数据类型xs:normalizedString的whiteSpace的值就是replace。
collapse:值中出现的每一个制表符、换行、回车都用一个空格进行替换,在替换后,所有连续空格都被压缩为一个空格,此外,前导空格和结尾空格都被删除。数据类型xs:token的whiteSpace值就是collapse。
注,whiteSpace只能用于基于字符串的类型。在实际应用,很少直接使用whiteSpace,而是选择已经具有whiteSpace的基类型,如:xs:string、xs:normalizedString、xs:token
fixed属性
除了enumeration和pattern外,都有一个fixed属性,类型为boolean,默认为false,如果为true,派生类型将不能修改值。
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="score" type="scoreType"/>
<xs:simpleType name="scoreType">
<xs:restriction base="xs:integer">
<xs:minInclusive value="0" fixed="true"/>
<xs:maxInclusive value="100" fixed="true"/>
</xs:restriction>
</xs:simpleType>
<!--下面的类型定义将引发错误
<xs:simpleType name="newScoreType">
<xs:restriction base="scoreType">
<xs:maxInclusive value="150"/>
</xs:restriction>
</xs:simpleType>
-->
</xs:schema>
列表类型
简单类型可分为三类:原子类型、列表类型(内置的有NMTOKENS、IDREFS、ENTITIES)、联合类型。
自定义列表类型
使用xs:list元素可自定义新的列表类型,使用itemType属性引用一个现有的原子类型。
不能使用现有的列表类型来创建新的列表类型,也不能使用复杂类型来创建新的列表类型。
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="municipalities">
<xs:simpleType>
<!--itemType引用一个现有原子类型,可以是内置的,也可以是派生的-->
<xs:list itemType="xs:token"/>
</xs:simpleType>
</xs:element>
</xs:schema>
<municipalities>北京市 上海市 天津市重庆市</municipalities>
也可在xs:list元素内部使用xs:simpleType子元素来指定匿名的原子类型:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="number" type="numberType"/>
<xs:simpleType name="numberType">
<xs:list>
<!--定义一个匿名的简单类型,它从内置的xs:positiveInteger类型派生 -->
<xs:simpleType>
<xs:restriction base="xs:positiveInteger">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="10"/>
</xs:restriction>
</xs:simpleType>
</xs:list>
</xs:simpleType>
</xs:schema>
限定列表类型
5个约束元素可应用于列表类型,它们是:length、minLength、maxLength、enumeration、pattern。
对列表使用length、minLength、maxLength:
<xs:element name="emails" type="emailsType"/>
<xs:simpleType name="emailsType">
<xs:restriction>
<xs:simpleType>
<xs:list itemType="xs:token"/>
</xs:simpleType>
<!--注,该约束是对整个list类型的约束,而不是对list中的项
进行约束,所以不能写在list内部,如果写在内容,则表示
list项中的内容最大长度是4。而这里表示是列表中最多允许
4项-->
<xs:maxLength value="4"/>
</xs:restriction>
</xs:simpleType>
对列表使用enumeration:
<xs:element name="number" type="numberType"/>
<xs:simpleType name="numberType">
<xs:list>
<xs:simpleType>
<xs:restriction base="xs:token">
<!--注,enumeration与length、minLength、maxLength三个元素
不一样,它需要定义在list内部,因为实际上是对list列表每一
项进行的约束。如果写在外面,则列表只能取其一-->
<xs:enumeration value="I"/>
<xs:enumeration value="II"/>
<xs:enumeration value="III"/>
<xs:enumeration value="IV"/>
<xs:enumeration value="V"/>
</xs:restriction>
</xs:simpleType>
</xs:list>
</xs:simpleType>
<number>I II III IV V </number>
对列表使用pattern:
<xs:element name="number" type="numberType"/>
<xs:simpleType name="numberType">
<xs:list>
<xs:simpleType>
<xs:restriction base="xs:token">
<!--注,pattern与enumeration一样也要定义在list内部,否则只能有一个值-->
<xs:pattern value="\d"/>
</xs:restriction>
</xs:simpleType>
</xs:list>
</xs:simpleType>
<number>1 2 3</number>
联合类型
联合类型可以包含多个原子类型或列表类型(甚至是其他联合类型),组成联合类型的简单类型称为它的成员类型,成员类型必须是简单类型,不能是复杂类型。
自定义联合类型
使用xs:union元素可自定义联合类型,该元素的memberTypes属性给出组成联合类型的所有成员类型,各个成员之间使用空白符分开,或在xs:union元素内使用一个或多个xs:simpleType子元素来指定匿名的成员类型。
使用memberTypes属性来定义联合类型:
<xs:element name="employee">
<!--定义了一个匿名的联合类型 -->
<xs:simpleType>
<xs:union memberTypes="xs:positiveInteger xs:token"/>
</xs:simpleType>
</xs:element>
符合上面模式的实例文档:
<employee>101</employee> 或 <employee>张三</employee>
在xs:union元素内部使用xs:simpleType子元素来指定一个匿名简单类型作为联合类型的成员类型:
<xs:element name="number" type="numberType"/>
<xs:simpleType name="numberType">
<xs:union>
<!--联合类型的成员类型一,其值为1到5的正整数 -->
<xs:simpleType>
<xs:restriction base="xs:positiveInteger">
<xs:maxInclusive value="5"/>
</xs:restriction>
</xs:simpleType>
<!--联合类型的成员类型二,其值为I、II、III、IV、V其中之一 -->
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="I"/>
<xs:enumeration value="II"/>
<xs:enumeration value="III"/>
<xs:enumeration value="IV"/>
<xs:enumeration value="V"/>
</xs:restriction>
</xs:simpleType>
</xs:union>
</xs:simpleType>
符合上面模式的实例文档:
<number>5</number> 或 <number> V </number>
限制联合类型
enumeration和pattern可以应用于联合类型。
<xs:element name="number" type="numberType"/>
<xs:simpleType name="numberType">
<xs:restriction>
<xs:simpleType>
<xs:union memberTypes="xs:positiveInteger xs:token"/>
</xs:simpleType>
<!--对联合类型应用enumeration面 -->
<xs:enumeration value="1"/>
<xs:enumeration value="2"/>
<xs:enumeration value="3"/>
<xs:enumeration value="I"/>
<xs:enumeration value="II"/>
<xs:enumeration value="III"/>
</xs:restriction>
</xs:simpleType>
注,也只能取枚举类型中的某一个值,不能是组合
<number>1</number>
<xs:element name="number" type="numberType"/>
<xs:simpleType name="numberType">
<xs:restriction>
<xs:simpleType>
<xs:union memberTypes="xs:positiveInteger xs:token"/>
</xs:simpleType>
<xs:pattern value="-\d"/>
</xs:restriction>
</xs:simpleType>
注,其实enumeration与pattern也都可以写在union内部,但它们只能用在列表类型内部,否则不正确。
阻止简单类型派生
xs:smipleType的属性final可用来阻止派生,其取值如下:
#all:表示阻止任何种类(限制、列表、联合)的派生
restriction:阻止限制派生
list:阻止列表派生
union:阻止联合派生
如果没有使用final属性,那么它的默认值将是xs:schema元素的finalDefault属性值,如果要取消finalDefault属性值,那么可以将xs:simpleType元素的final属性设置为空字符串
<xs:element name="score" type="scoreType"/>
<xs:simpleType name="scoreType" final="#all">
<xs:restriction base="xs:token">
<xs:enumeration value="A"/>
<xs:enumeration value="B"/>
</xs:restriction>
</xs:simpleType>
复杂类型
元素如果包含子元素或者带有属性则称为复杂类型,使用 xs:complexType元素来定义。
复杂类型要么具有简单内容,要么具有复杂内容。元素的“内容”是指在它的开始标签与结束标签之间的字符数据和子元素。简单内容指的是它只包含字符数据内容,而没有子元素(可以有属性),简单内容使用xs:simpleContent元素来定义;除此之外元素内容为复杂内容,使用xs:complexContent元素来定义。
简单内容类型(xs:simpleContent)的复杂元素要求必须含有文本,可以有属性,也可以没有,但不能有子元素。
复杂内容类型(xs:complexContent)的复杂元素可以有属性、子元素(没有子元素时就成空元素了),也可以没有,但不能有文本。
XMLSchema类型的派生分为限制(restriction)和扩展(extension),通过限制派生的新类型的值范围是原类型值范围的子集,通过扩展可以为现有类型添加新的元素和属性。
我们可以通过扩展(extension)为现有类型添加新的元素和属性,也可从xs:anyType类型限制派生(restriction)来定义新的复杂类型。
从简单内置类型派生复杂类型
对于 <book>Struts 2深入详解<book> 这个元素的简单类型定义:
<xs:element name="book" type="xs:token"/>
如果现为book元素添加一个属性isbn,则需要从内置简单类型派生出复杂类型:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="book">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:token">
<!--在简单内置类型的基础上添加属性,成为复杂类型-->
<xs:attribute name="isbn" type="xs:token"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:schema>
<book isbn="978-7-121-06812-6"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="例7-1.xsd">
《Struts 2深入详解》
</book>
xs:attribute元素的use、default和fixed属性
use的取值如下:
l optional:表明属性是可选的,默认值就是可选。
l prohibited:禁止使用这个属性。
l required:属性是必需的。
注,对于声明的全局属性不能使用use属性。
default用来设置元素属性的默认值,如果在XML文档中没有指定声明的这个属性,那么处理器就认为该属性的值等于声明中的default属性值。要注意,属性的默认值只有在属性本身为“optional”时才有意义,也就是说,属性使用默认值的时候,use属性的值只能是optional。
如果想让某个元素的属性值固定下来,不允许修改时,可以使用xs:attribute元素的fixed属性来指定一个固定的默认值。
注,default与fixed不能同时使用。
anyType
anyType是派生所有简单和复杂类型的基类型,它是XML Schema中所有类型的祖先。如果一元素的类型具有anyType类型,那么它的内容将可以是任何形式。
实际上,anyType是默认类型,在声明一个元素时,如果没有指定类型时,就是该类型。
纯元素内容
如果元素的内容中只包含子元素,而没有字符数据,则为纯元素内容。我们可以使用模型组(xs:sequence、xs:choice、xs:all)来构建纯元素内容的内容模式。
xs:sequence
表示序列,sequence组中的所有子元素要按照指定的顺序出现。
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="empType"/>
<xs:complexType name="empType">
<!--使用xs:complexContent元素来定义复杂内容 -->
<xs:complexContent>
<!--从xs:anyType类型限制派生。复杂内容的限制派生
使用的基类型是xs:anyType类型,或者它的派生类型 -->
<xs:restriction base="xs:anyType">
<!--使用sequence组。在xs:sequence元素内部子元素声明的顺序,
也就是实例文档中子元素出现的顺序-->
<xs:sequence>
<!--声明name元素 -->
<xs:element name="name" type="xs:token"/>
<!--声明age元素 -->
<xs:element name="age">
<xs:simpleType>
<xs:restriction base="xs:positiveInteger">
<xs:minInclusive value="18"/>
<xs:maxExclusive value="60"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
<?xml version="1.0" encoding="GB2312"?>
<employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="例7-4.xsd">
<name>张三</name>
<age>25</age>
</employee>
XMLSchema规定,如果一个具有复杂内容的复杂类型定义是从anyType类型限制派生(<xs:restriction base="xs:anyType">),那么可以省略 xs:complexContent和 xs:restriction 元素,而直接在 xs:complexType下使用模型组(xs:sequence、xs:choice、xs:all):
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="empType"/>
<xs:complexType name="empType">
<xs:sequence>
<!--声明name元素 -->
<xs:element name="name" type="xs:token"/>
<!--声明age元素 -->
<xs:element name="age">
<xs:simpleType>
<xs:restriction base="xs:positiveInteger">
<xs:minInclusive value="18"/>
<xs:maxExclusive value="60"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:schema>
xs:choice
表示选择,choice组中的所有子元素可以选择使用任意一个,且只能使用一个,且一定要有一个。
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="empType"/>
<xs:complexType name="empType">
<xs:choice>
<xs:element name="telephone">
<xs:simpleType>
<xs:restriction base="xs:token">
<!--电话格式为:3到4位区号,中间接一个短横线(-),
之后是6到8位电话号码 -->
<xs:pattern value="\d{3,4}-\d{6,8}"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="mobile">
<xs:simpleType>
<xs:restriction base="xs:token">
<!--手机格式为:11数字组成的号码 -->
<xs:pattern value="\d{11}"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:schema>
<?xml version="1.0" encoding="GB2312"?>
<employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="例7-7.xsd">
<mobile>12341234111</mobile>
<!--或者使用telephone元素
<telephone>010-12345678</telephone>
-->
</employee>
组合使用sequence组和choice组:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee">
<xs:complexType>
<xs:sequence>
<xs:sequence><!--下面三个按顺序出现-->
<xs:element name="name" type="xs:token"/>
<xs:element name="age" type="xs:positiveInteger"/>
<xs:element name="gender" type="xs:token"/>
</xs:sequence>
<xs:choice><!--下面两个只能选一个,且一定要选一个-->
<xs:element name="telephone" type="xs:token"/>
<xs:element name="mobile" type="xs:token"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
xs:all
表示任意次序,all组中的所有子元素可以以任意顺序出现,且都要出现。
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="empType"/>
<xs:complexType name="empType">
<xs:all>
<xs:element name="number" type="xs:integer"/>
<xs:element name="name" type="xs:token"/>
</xs:all>
</xs:complexType>
</xs:schema>
<?xml version="1.0" encoding="GB2312"?>
<employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="例7-11.xsd">
<name>张三</name>
<number>101</number>
</employee>
xs:all组不能和其他的模型组(sequence组和choice组)一起使用(但可以有属性),而它必须出现在内容模型的顶部,下面违反了三条规则:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="empType"/>
<xs:complexType name="empType">
<xs:sequence>
<xs:attribute name="attr" type="xs:string"/>
<!-- all组不能在xs:sequence元素内部使用,而且也不能和
sequence组一起并排使用,而且如果出现也只能出现在内
容模型顶部-->
<xs:all>
<xs:element name="number" type="xs:integer"/>
<xs:element name="name" type="xs:token"/>
</xs:all>
<xs:sequence>
<xs:element name="age" type="xs:positiveInteger"/>
<xs:element name="gender" type="xs:token"/>
</xs:sequence>
</xs:sequence>
</xs:complexType>
</xs:schema>
正确的只能这样:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="empType"/>
<xs:complexType name="empType">
<xs:all>
<xs:element name="number" type="xs:integer"/>
<xs:element name="name" type="xs:token"/>
</xs:all>
<!--不能放在最顶部,只能放在all的下面-->
<xs:attribute name="attr" type="xs:string"/>
</xs:complexType>
</xs:schema>
元素的出现次数限制
可以使用两个属性:minOccurs和maxOccurs来指定元素出现的次数,这两个属性可以在 xs:element 或模型组元素(xs:sequence、xs:choice、xs:all)上使用,它们的默认值都是1。
在xs:element上使用minOccurs和maxOccurs:
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="empType"/>
<xs:complexType name="empType">
<!--interest或skill子元素可以出现0次或多次,
无论出现多少次,interest元素必须在skill元素之前出现-->
<xs:sequence>
<xs:element name="interest" type="xs:token"
minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="skill" type="xs:token"
minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
<?xml version="1.0" encoding="GB2312"?>
<employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="例7-14.xsd">
<interest>足球</interest>
<interest>篮球</interest>
</employee>
在xs:sequence上使用minOccurs和maxOccurs:
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="empType"/>
<xs:complexType name="empType">
<!--interest和skill元素必须一起出现0次或多次-->
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="interest" type="xs:token"/>
<xs:element name="skill" type="xs:token"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
<?xml version="1.0" encoding="GB2312"?>
<employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="例7-14.xsd">
<interest>足球</interest>
<skill>Java</skill>
<interest>篮球</interest>
<skill>C++</skill>
</employee>
在xs:choice上使用minOccurs和maxOccurs:
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="empType"/>
<xs:complexType name="empType">
<!--
telephone或mobile子元素在单独出现时,最多可以出现2次;
telephone和mobile子元素一起出现时,各自只能出现一次,
不过,出现的次序可以任意的
-->
<xs:choice maxOccurs="2">
<xs:element name="telephone" type="xs:token"/>
<xs:element name="mobile" type="xs:token"/>
</xs:choice>
</xs:complexType>
</xs:schema>
在all组中声明的元素都不能出现超过一次,也就是说,在使用xs:all元素定义的内容模型时,xs:all元素本身和其内的xs:element元素的minOccurs和maxOccurs属性值只能是0或1,xs:all元素的maxOccurs属性必须是1。
元素的默认值与固定值
除了属性以外,元素也有默认值,使用xs:element元素的default属性来定义默认值。
<xs:element name="format" type="xs:token" default="PDF"/>
<format/> 与 <format></format> 都将使用默认值。
<format> </format>将使用空格,不会使用默认值。
<xs:element name="format" type="xs:token" fixed="PDF"/>
<format/> 与 <format></format>、<format>PDF</format>都将使用固定值。
<format> </format>将报错。
空元素
anyType是默认类型,在声明一个元素时,如果没有指定类型时,就是该类型。所以如果要定义一个空元素,则需要手工指定。
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!--
<xs:element name="student">
<xs:complexType>
<xs:complexContent>
<xs:restriction base="xs:anyType">
<xs:attribute name="number" type="xs:token"/>
<xs:attribute name="name" type="xs:token"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:element>
-->
<!--下面是简化的写法-->
<xs:element name="student">
<!--没有子元素,所以是空元素-->
<xs:complexType>
<xs:attribute name="number" type="xs:token"/>
<xs:attribute name="name" type="xs:token"/>
</xs:complexType>
</xs:element>
</xs:schema>
<student number="001" name="张三"/>
混合内容
如果一个元素既包含子元素,又包含字符数据,那么称元素的内容为混合内容。要定义混合内容类型,可以将xs:complexType元素的mixed属性设置为true。
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="empType"/>
<xs:complexType name="empType" mixed="true">
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:element name="age" type="xs:positiveInteger"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
<?xml version="1.0" encoding="GB2312"?>
<employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="例7-25.xsd">
雇员:
<name>张三</name>
年龄:
<age>25</age>
</employee>
元素组
将多个元素定义在一个全局组里,供后面重用。
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="company" type="companyType"/>
<xs:complexType name="companyType">
<!--company元素的内容中可以出现1到多个employee子元素,
以及0到多个manager子元素(表示管理人员)-->
<xs:sequence>
<xs:element name="employee" type="empType" maxOccurs="unbounded"/>
<xs:element name="manager" type="mgrType" minOccurs="0"
maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="empType">
<xs:sequence> <!--此处的xs:sequence可以省,因为这个组的引用就是该复杂类型的整个内容模型,这与下面的 mgrType 复杂类型不一样-->
<!--引用元素组 -->
<xs:group ref="empGroup"/>
</xs:sequence>
</xs:complexType>
<!--定义元素组 -->
<xs:group name="empGroup">
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:element name="age" type="xs:positiveInteger"/>
</xs:sequence>
</xs:group>
<xs:complexType name="mgrType">
<xs:sequence>
<!--引用元素组 -->
<xs:group ref="empGroup"/>
<!--管理人员有津贴,用allowance元素来表示 -->
<xs:element name="allowance" type="xs:decimal"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
注,xs:group元素中不能直接使用xs:element元素,必须先使用模型组。另外,xs:group元素本身和它内部模型组都不能使用出现指示符(minOccurs和maxOccurs属性),如果希望出现多次,可以在引用元素时使用(<xs:group ref="empGroup" minOccurs="1" maxOccurs="unbounded"/>)。
属性组
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- order元素表示图书订单 -->
<xs:element name="order" type="orderType"/>
<!--属性组定义,包含了两个属性声明 -->
<xs:attributeGroup name="baseAttrGroup">
<xs:attribute name="number" type="xs:token" use="required"/>
<xs:attribute name="totalPrice" type="xs:decimal" use="required"/>
</xs:attributeGroup>
<xs:attributeGroup name="extraAttrGroup">
<!--定义属性组时也可以引用其他的属性组 -->
<xs:attributeGroup ref="baseAttrGroup"/>
<xs:attribute name="orderTime" type="xs:dateTime"/>
</xs:attributeGroup>
<xs:complexType name="orderType">
<xs:sequence>
<!-- item元素表示订单项,一份订单可以有多个订单项 -->
<xs:element name="item" type="itemType" maxOccurs="unbounded"/>
</xs:sequence>
<!--引用属性组,属性组中的number属性表示订单编号,
totalPrice属性表示订单总价格-->
<xs:attributeGroup ref="baseAttrGroup"/>
<!-- orderDate元素表示订单时间 -->
<xs:attribute name="orderTime" type="xs:dateTime"/>
</xs:complexType>
<xs:complexType name="itemType">
<xs:sequence>
<!-- title元素表示图书标题 -->
<xs:element name="title" type="xs:token"/>
<!-- amount元素表示购买数量 -->
<xs:element name="amount" type="xs:positiveInteger"/>
<!-- price元素表示图书单价 -->
<xs:element name="price" type="xs:decimal"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
元素通配符xs:any
实例文档中的xs:any元素出现的位置可以使用任意元素来替换,它有4个属性:minOccurs、maxOccurs、namespace和processContents。
minOccurs、maxOccurs属性用于控制替换元素出现的次数,但不包括替换元素的子元素,默认值都是1。
namespace属性用于指定替换元素所属的名称空间,默认值为 ##any,表示替换元素可以在任何名称空间,或不在任何名称空间。##other 表示替换元素可以在除模式文档目标名称空间之外的任何名称空间中,如果没有目标名称空间,则替换元素可以属于任何名称空间,且必须属于一个名称空间。除了这两个值外,还可以是下列值:
##targetNamespace:替换元素可以在模式文档的目标名称空间中。
##local:替换元素不在任何名称空间中。
替换元素的特定名称空间:指出替换元素所在的名称空间URI,多个使用空白符分开。
注,名称空间约束只适用于替换元素,子元素根据替换元素本身的类型进行验证。
processContents属性用于指示模式处理器如何对替换元素进行验证,取值如下:
strict:默认值。找namespace属性指定的模式文档,如果找不到或验证失败,则报错。
lax:如果找不到,则不报错,如果找到且验证失败,则报错。
skip:不执行任何验证,但替换元素必须在namespace属性所允许的一个名称空间中。
--例7-31.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xs:element name="person">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<!--namespace属性未指定,默认为 ##any ,即任何名称
空间的元素都可以,又处理机制为 lax ,所以在验证
时不会去找模式文档,也不会验证-->
<xs:any processContents="lax"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
<?xml version="1.0" encoding="GB2312"?>
<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="例7-31.xsd">
<name>张三</name>
<!--模式文档中未指明 namespace,所以下面 children 可以是任何
名称空间中声明过的元素,而且模式文档中 xs:any 通配符也没
指定minOccurs与maxOccurs,所以采用默认值1,因这里的children
元素仅只能出现一次,且一定要出现。-->
<children>
<!--注,xs:any元素的属性设置对替换元素children的子元素没有
影响,子元素根据替换元素children本身的类型进行验证,又
因为模式文档中没有对children进行类型定义,所以子元素也
就没有任何限制了-->
<name>张小明</name>
<age>8</age>
</children>
</person>
将模式文档中的“<xs:any processContents="lax"/>”替换成下面的内容,下面虽然模式处理器不会对替换元素进行验证(processContents="skip"),但是仍然要求替换元素在namespace属性所指定的名称空间中。
<xs:any processContents="skip" namespace="http://www.sunxin.org/family"/>
<?xml version="1.0" encoding="GB2312"?>
<person xmlns:family="http://www.sunxin.org/family"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="例7-31.xsd">
<name>张三</name>
<family:children>
<name>张小明</name>
<age>8</age>
</family:children>
</person>
如果将上面的skip改为lax,则“验证”还是可以通过,因为实例文档并没有给出与http://www.sunxin.org/family名称空间相关的模式文档的位置,所以解析器无法找到替换元素的声明来对替换元素进行验证,所以也不会报错。但如果修改成 strict 时,上面的实例文档将不能通过验证。
如果将上面的skip修改成strict,则实例文档中的children需要在某个模式文档进行声明过,否则验证不通过:
--实例文档:
<?xml version="1.0" encoding="GB2312"?>
<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="例7-31.xsd"
xsi:schemaLocation="http://www.sunxin.org/family family.xsd"
xmlns:family="http://www.sunxin.org/family">
<name>张三</name>
<family:children>
<name>张小明</name>
<age>8</age>
</family:children>
</person>
上面实例文档中的元素声明来自两个模式文档:“例7-31.xsd”与“family.xsd”,在进行验证时,会到这两个模式文档中去是否对相应元素进行了声明,并进行有效行验证。
--family.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.sunxin.org/family"
targetNamespace="http://www.sunxin.org/family">
<xs:element name="children" type="childrenType"/>
<xs:complexType name="childrenType">
<xs:sequence>
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:element name="age" type="xs:positiveInteger"/>
</xs:sequence>
</xs:sequence>
</xs:complexType>
</xs:schema>
属性通配符xs:anyAttribute
实例文档中的xs:anyAttribute元素出现的位置可以使用任意属性来替换,它有2个属性: namespace和processContents,其意义与元素通配符作用完全相同。但xs:anyAttribute没有minOccurs、maxOccurs两个属性,因为属性通配符无须任何指定,就可以有任意多个替换属性。
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="person">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:token"/>
</xs:sequence>
<xs:anyAttribute namespace="##local" processContents="strict"/>
</xs:complexType>
</xs:element>
<!--因为processContents="strict",所以在实例文档中出现的属性一定要
在某个模式文档中进行先声明,否则验证不通过,当做如果为 skip时,则
无须声明-->
<xs:attribute name="idCard"/>
<xs:attribute name="married"/>
</xs:schema>
<?xml version="1.0" encoding="GB2312"?>
<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="例7-36.xsd"
idCard="1001001980081021110" married="yes">
<name>张三</name>
</person>
派生复杂类型
在XMLSchema中没有内置的复杂类型,复杂类型都是通过限制或扩展其他的类型来派生的。
当从简单类型或另一个具有简单内容(元素内容只包含字符数据,可以有属性)的复杂类型派生复杂类型时,使用xs:simpleContent元素。如果是扩展派生(添加属性),则在xs:simpleContent元素内部使用xs:extension元素;如果是限制派生(限制基类型的内容),则在xs:simpleContent元素内部使用xs:restriction元素。
如果复杂类型具有简单内容,那么所有直接或间接派生于它的类型也只能具有简单内容,如果在派生的过程中试着将简单内容转换为复杂内容时,会报错,不能将简单内容转换成复杂内容:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="studentType">
<xs:simpleContent>
<!--基类型派生自简单的内置类型,成为简单内容的复杂类型-->
<xs:extension base="xs:string">
<xs:attribute name="number" type="xs:integer"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="derivedStudentType">
<xs:simpleContent>
<!--尝试派生自简单内容-->
<xs:extension base="studentType">
<!--注,不能从简单内容派生出复杂内容,所以这里会报错-->
<xs:sequence>
<xs:element name="name" type="xs:token"/>
</xs:sequence>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>
复杂内容包括3种内容类型:纯元素类型、混合类型、空内容类型。
扩展派生复杂类型
扩展简单内容
扩展简单内容可以从简单类型扩展,也可以从具有简单内容的复杂类型进行扩展。由于不能通过扩展简单内容来得到复杂内容,因此对简单内容的扩展只能是添加新的属性。
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="expandedEmpType"/>
<!--从内置的简单类型扩展派生出复杂类型-->
<xs:complexType name="empType">
<xs:simpleContent>
<xs:extension base="xs:token">
<!-- number属性表示员工编号 -->
<xs:attribute name="number" type="xs:token" use="required"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!--从具有简单内容的复杂类型扩展派生,但不能转换成复杂内容,所以派生出的内容还是简单内容-->
<xs:complexType name="expandedEmpType">
<xs:simpleContent>
<xs:extension base="empType">
<!-- hiredate属性表示员工雇佣日期 -->
<xs:attribute name="hiredate" type="xs:date"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:schema>
<employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="例8-2.xsd"
number="101" hiredate="2008-07-01">张三</employee>
扩展纯元素内容
从纯元素内容的复杂类型扩展,我们可以在基类型的内容模型最后添加新的元素或属性。解析器将把基类型的内容模型和新添加的内容模型合并到一个新建的sequence组中。
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="expandedEmpType"/>
<!--具有纯元素内容的复杂类型 -->
<xs:complexType name="empType">
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:element name="age" type="xs:positiveInteger"/>
</xs:sequence>
</xs:complexType>
<!--从纯元素内容的复杂类型扩展 -->
<xs:complexType name="expandedEmpType">
<xs:complexContent>
<xs:extension base="empType">
<!--在基类型empType的内容模型的最后添加choice组和number属性 -->
<xs:choice>
<xs:element name="telephone" type="xs:token"/>
<xs:element name="mobile" type="xs:token"/>
</xs:choice>
<xs:attribute name="number" type="xs:token" use="required"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
扩展empType类型后的expandedEmpType类型等价于下面的类型定义:
<xs:complexType name="expandedEmpType">
<xs:sequence>
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:element name="age" type="xs:positiveInteger"/>
</xs:sequence>
<xs:choice>
<xs:element name="telephone" type="xs:token"/>
<xs:element name="mobile" type="xs:token"/>
</xs:choice>
</xs:sequence>
<xs:attribute name="number" type="xs:token" use="required"/>
</xs:complexType>
<?xml version="1.0" encoding="GB2312"?>
<employee number="101" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="例8-4.xsd">
<name>张三</name>
<age>25</age>
<mobile>12341008888</mobile>
</employee>
下面再看一个扩展choice组的例子:
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="fruit" type="expandedFruitType"/>
<!--基类型包含一个choice组 -->
<xs:complexType name="fruitType">
<xs:choice>
<xs:element name="apple" type="xs:token"/>
<xs:element name="pear" type="xs:token"/>
<xs:element name="banana" type="xs:token"/>
</xs:choice>
</xs:complexType>
<!--派生类型添加了一个新的choice组 -->
<xs:complexType name="expandedFruitType">
<xs:complexContent>
<xs:extension base="fruitType">
<xs:choice>
<xs:element name="peach" type="xs:token"/>
<xs:element name="orange" type="xs:token"/>
</xs:choice>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
上面我们本意是将peach和orange元素添加到基类型choice组中,以便可以在5个子元素中任意选择其中一个,但结果不是我们所想那样,它等价于下面类型:
<xs:complexType name="expandedFruitType">
<xs:sequence>
<xs:choice>
<xs:element name="apple" type="xs:token"/>
<xs:element name="pear" type="xs:token"/>
<xs:element name="banana" type="xs:token"/>
</xs:choice>
<xs:choice>
<xs:element name="peach" type="xs:token"/>
<xs:element name="orange" type="xs:token"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
也就是说,通过添加一个新的choice组来扩展choice组,其结果并不是两个choice组的元素合并在一起,而是产生了一个包含两个choice组的sequence组。
不能对一个包含all组的基类型进行扩展来添加新的元素(只添加属性是可以的),这是因为all组不能和其他模型组(xs:sequence组和choice组)一起使用,而且它必须出现在内容模型的顶部。
扩展混合内容
混合内容的扩展与纯元素内容的扩展类似,唯一要求是派生类型必须也是混合内容,也就是说,在定义派生类型时,xs:complexType元素的mixed属性也必须设为true。
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="expandedEmpType"/>
<!--具有混合内容的复杂类型 -->
<xs:complexType name="empType" mixed="true">
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:element name="age" type="xs:positiveInteger"/>
</xs:sequence>
</xs:complexType>
<!--从具有混合内容的复杂类型扩展 -->
<xs:complexType name="expandedEmpType" mixed="true">
<xs:complexContent mixed="true">
<xs:extension base="empType">
<xs:sequence>
<xs:element name="salary" type="xs:decimal"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
<?xml version="1.0" encoding="GB2312"?>
<employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="例8-8.xsd">
雇员:<name>张三</name>
年龄:<age>25</age>
薪水:<salary>2000</salary>
</employee>
扩展空内容
从空内容类型扩展,派生类型可以具有纯元素内容(通过添加元素),也可以具有混合内容(通过将派生类型的mixed属性设置为true)。
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="extendedEmpType"/>
<!--具有空内容的复杂类型 -->
<xs:complexType name="empType">
<xs:attribute name="number" type="xs:token"/>
</xs:complexType>
<!--从空内容类型扩展 -->
<xs:complexType name="extendedEmpType">
<xs:complexContent>
<xs:extension base="empType">
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:element name="age" type="xs:positiveInteger"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
限制派生复杂类型
限制简单内容
与扩展简单内容不同,限制简单内容的基类型必须是具有简单内容的复杂类型,而不能是简单类型,因为简单类型的限制是另一个简单类型,而不是复杂类型。
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="telephone" type="restrictedTelType"/>
<!--具有简单内容的复杂类型 -->
<xs:complexType name="telType">
<xs:simpleContent>
<!--属性type表示电话号码类型 -->
<xs:extension base="xs:token">
<xs:attribute name="type" type="xs:token"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<!--从具有简单内容的复杂类型限制派生 -->
<xs:complexType name="restrictedTelType">
<xs:simpleContent>
<xs:restriction base="telType">
<!--限制区号为3到4个字符,号码为6到8个字符,中间以-连接。 -->
<xs:pattern value="\d{3,4}-\d{6,8}"/>
<xs:attribute name="type">
<xs:simpleType>
<!--限制电话号码类型只能是office或者home。-->
<xs:restriction base="xs:token">
<xs:enumeration value="office"/>
<xs:enumeration value="home"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:restriction>
</xs:simpleContent>
</xs:complexType>
</xs:schema>
<?xml version="1.0" encoding="GB2312"?>
<telephone xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="例8-12.xsd" type="office">010-66668888</telephone>
限制纯元素内容
可以限制元素的内容或属性的取值,及删除元素或属性,对于需要从基类型保留的元素和属性则需要重新声明。
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="employee" type="restrictedEmpType"/>
<!--具有纯元素内容的复杂类型 -->
<xs:complexType name="empType">
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:element name="age" type="xs:integer"/>
<!--需要将minOccurs设为0,否则在派生类型中将不能删除email元素-->
<xs:element name="email" type="xs:token" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<!--从具有纯元素内容的复杂类型限制派生 -->
<xs:complexType name="restrictedEmpType">
<xs:complexContent>
<xs:restriction base="empType">
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:element name="age" type="xs:positiveInteger"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
限制混合内容
从具有混合内容的复杂类型限制派生,可以得到混合内容的复杂类型、纯元素内容的复杂类型、简单内容的复杂类型,甚至是空内容的复杂类型。
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!--具有混合内容的复杂类型 -->
<xs:complexType name="empType" mixed="true">
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:element name="age" type="xs:positiveInteger"/>
<!--需要将minOccurs设为0,否则在派生类型中将不能删除email元素-->
<xs:element name="email" type="xs:token" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<!--从具有混合内容的复杂类型限制派生得到混合内容的复杂类型-->
<xs:complexType name="restrictedEmpType1" mixed="true">
<xs:complexContent mixed="true">
<xs:restriction base="empType">
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:element name="age" type="xs:positiveInteger"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
<!--
从具有混合内容的复杂类型限制派生得到纯元素内容的复杂类型。
没有为派生类型指定mixed属性(默认值为false)
-->
<xs:complexType name="restrictedEmpType2">
<xs:complexContent>
<xs:restriction base="empType">
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:element name="age" type="xs:positiveInteger"/>
<xs:element name="email" type="xs:token"/>
</xs:sequence>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!--具有混合内容的复杂类型,内容模型中所有的子元素都是可选的 -->
<xs:complexType name="empType" mixed="true">
<xs:sequence>
<xs:element name="name" type="xs:token" minOccurs="0"/>
<xs:element name="age" type="xs:positiveInteger" minOccurs="0"/>
<xs:element name="email" type="xs:token" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<!--
从具有混合内容的复杂类型限制派生得到简单内容的复杂类型。
派生类型的mixed属性为true,因此元素内容可以有字符数据,
但由于派生类型没有声明任何子元素,因此元素内容中不能有子元素
-->
<xs:complexType name="restrictedEmpType1" mixed="true">
<xs:complexContent mixed="true">
<xs:restriction base="empType"/>
</xs:complexContent>
</xs:complexType>
<!--
从具有混合内容的复杂类型限制派生得到空内容的复杂类型。
派生类型没有指定mixed属性,同时又没有声明任何子元素,
因此,派生类型是一个空内容的复杂类型
-->
<xs:complexType name="restrictedEmpType2">
<xs:complexContent>
<xs:restriction base="empType"/>
</xs:complexContent>
</xs:complexType>
</xs:schema>
限制空内容
限制空内容只能对基类型的属性进行限制,派生类型也必须是空内容。
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!--元素直接使用派生类型 restrictedEmpType-->
<xs:element name="employee" type="restrictedEmpType"/>
<!--具有空内容的复杂类型 -->
<xs:complexType name="empType">
<xs:attribute name="number" type="xs:integer"/>
</xs:complexType>
<!--从具有空内容的复杂类型派生,派生类型也必须有空内容 -->
<xs:complexType name="restrictedEmpType">
<xs:complexContent>
<xs:restriction base="empType">
<!--限制属性值必须是正整数,限制属性是必需的 -->
<xs:attribute name="number" type="xs:positiveInteger" use="required"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
在实例文档中使用派生类型
在上面“限制空内容”节中的例子中(前面所有元素类型引用都是这样直接指定派生类型),都是为声明的元素直接指定派生类型,从而在实例文档中依照派生类型来为元素或属性设值,但我们也可以不在声明元素时直接指定派生类型,甚至不指定类型(默认为 ##anyType),而是在XML文档中使用时通过xsi:type属性来显式地指定类型。xsi:type属性是XMLSchema实例名称空间http://www.w3.org/2001/XMLSchema-instance的一部分。
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="netstore" type="storeType"/>
<xs:complexType name="storeType">
<xs:sequence>
<xs:element name="items">
<xs:complexType>
<xs:sequence>
<!-- items元素的内容中可以0到多个商品项 -->
<xs:element ref="item" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<!--声明item元素的类型为itemType,可以在XML实例文档中指定派生类型来覆盖此基类型-->
<xs:element name="item" type="itemType"/>
<!--商品项的基类型定义 -->
<xs:complexType name="itemType">
<xs:sequence>
<xs:element name="id" type="xs:positiveInteger"/>
<xs:element name="title" type="xs:token"/>
<xs:element name="bookconcern" type="xs:token"/>
</xs:sequence>
</xs:complexType>
<!--图书商品类型定义,从基类型扩展派生,添加了pageCount元素 -->
<xs:complexType name="bookType">
<xs:complexContent>
<xs:extension base="itemType">
<xs:sequence>
<xs:element name="pageCount" type="xs:positiveInteger"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<!--音像商品类型定义,从基类型扩展派生,添加了format元素 -->
<xs:complexType name="videoType">
<xs:complexContent>
<xs:extension base="itemType">
<xs:sequence>
<xs:element name="format">
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="VCD"/>
<xs:enumeration value="DVD"/>
<xs:enumeration value="VHS"/>
<xs:enumeration value="CDROM"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
<?xml version="1.0" encoding="GB2312"?>
<netstore xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="例8-20.xsd">
<items>
<item xsi:type="bookType">
<id>1</id>
<title>Struts 2深入详解</title>
<bookconcern>电子工业出版社</bookconcern>
<pageCount>674</pageCount>
</item>
<item xsi:type="videoType">
<id>2</id>
<title>Java 无难事</title>
<bookconcern>电子工业出版社</bookconcern>
<format>CDROM</format>
</item>
</items>
</netstore>
替换组
替换组(substitution group),允许在模式中声明的某个元素被其他元素所替换。替换组由头元素和替换成员组成,头元素与它的替换成员都必须作为全局元素声明,替换成员必须与头元素有相同类型,或是头元素类型的派生类型。头元素是普通的全局元素,但它的替换成员则需要使用一个特殊的属性substitutionGroup,该属性用于指定要替换的头元素的名字。
修改上节例子:
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="netstore" type="storeType"/>
<xs:complexType name="storeType">
<xs:sequence>
<xs:element name="items">
<xs:complexType>
<xs:sequence>
<xs:element ref="item" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<!--全局声明的item元素作为替换组的头元素 -->
<xs:element name="item" type="itemType"/>
<!--
全局声明的book和video元素作为替换组的成员。
使用substitutionGroup属性指定要替换的头元素
-->
<xs:element name="book" type="bookType" substitutionGroup="item"/>
<xs:element name="video" type="videoType" substitutionGroup="item"/>
。。。。。。。。。。。。。。。。。
<?xml version="1.0" encoding="GB2312"?>
<netstore xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="例8-22.xsd">
<items>
<book>
<id>1</id>
<title>Struts 2深入详解</title>
<bookconcern>电子工业出版社</bookconcern>
<pageCount>674</pageCount>
</book>
<video>
<id>2</id>
<title>Java 无难事</title>
<bookconcern>电子工业出版社</bookconcern>
<format>CDROM</format>
</video>
</items>
</netstore>
抽象元素和类型
一个元素和类型可以被声明成抽象的,抽象元素和类型不能在实例文档中使用。将一个元素声明为抽象的,就需要使用替换组,在实例文档中用替换组成员来代替抽象元素,将一个元素对应的类型定义为抽象的,那么该元素的所有实例都必须使用xsi:type属性来指定一个非抽象的派生类型。
我们可以将上面例子中的“<xs:element name="item" type="itemType"/>”元素声明成抽象的,这样就只能使用book和video元素来替换item元素了,而不能在实例文档中直接使用item元素:
<xs:element name="item" type="itemType"abstract="true"/>
再回到“在实例文档中使用派生类型”节中的例子,将“<xs:complexType name="itemType">
”定义成抽象类型:
<xs:complexType name="itemType" abstract="true" > ...
则下面的item元素无法通过验证:
<item>
<id>1</id>
<title>Struts 2深入详解</title>
<bookconcern>电子工业出版社</bookconcern>
<pageCount>674</pageCount>
</item>
而将 item 元素类型通过 xsi:type 来指定其派生类就可以了:
<item xsi:type="bookType">
<id>1</id>
<title>Struts 2深入详解</title>
<bookconcern>电子工业出版社</bookconcern>
<pageCount>674</pageCount>
</item>
控制派生类型的创建和使用
可以使用xs:complexType元素的final属性来控制类型的派生,利用block属性来控制在实例文档中使用派生类型。
final取值如下:
l #all:阻止对该类型的任何形式(限制或扩展)的派生。
l extension:阻止对该类型的扩展派生。
l restriction:阻止对该类型限制派生。
l extension和restriction列表:等价于#all。
如果没有指定final属性,那它的值将是 xs:schema 元素的finalDefault属性的值。如果xs:schema元素指定了finalDefault属性,而在某个类型定义时我们想取消finalDefault属性的值,则可将该类型的final属性设为空字符串。block值也是这样的规则,只是使用bolockDefault而已。
block属性用于对派生类型在实例文档中的使用进行控制,取值如下:
l #all:阻止任何派生类型在实例文档中替换该类型。
l extension:阻止通过扩展派生的类型在实例文档中替换该类型。
l restriction:阻止通过限制派生的类型在实例文档中替换该类型。
l extension和restriction列表:等价于#all。
如果将“在实例文档中使用派生类型”节中的例子的“<xs:complexType name="itemType">
”元素修改为“<xs:complexType name="itemType" block="extendion">”,则上面章节中的XML实例文档将不能通过验证,因为实例文档中使用了itemType的扩展派生类型来替换了itemType类型。
除了可以在xs:complexType元素上使用block属性来控制派生类型在实例文档中的使用外,还可以在xs:element元素上使用block属性,作用与在xs:complexType上定义的是一样,除此外,其取值还可以是substitution,表示阻止替换组中的成员来替换该元素。
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="company" type="companyType"/>
<!--
companyType的内容模型包含一个address子元素和多个employee子元素。
address元素表示公司地址,employee元素表示公司的员工
-->
<xs:complexType name="companyType">
<xs:sequence>
<xs:element ref="address"/>
<xs:element name="employee" type="empType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<!-- empType的内容模型包含一个name子元素和一个homeAddress子元素 -->
<xs:complexType name="empType">
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:element ref="homeAddress"/>
</xs:sequence>
</xs:complexType>
<!--
声明address元素时,设置了block="extension",
阻止从addressType类型扩展派生的类型来替换addressType类型
-->
<xs:element name="address" type="addressType" block="extension"/>
<!-- homeAddress元素和address元素具有相同的类型 -->
<xs:element name="homeAddress" type="addressType"/>
<xs:complexType name="addressType">
<xs:sequence>
<xs:element name="country" type="xs:token"/>
<xs:element name="city" type="xs:token"/>
<xs:element name="street" type="xs:token"/>
</xs:sequence>
</xs:complexType>
<!--
derivedAddressType类型从addressType类型扩展派生,
添加了一个表示邮政编码的zipCode元素
-->
<xs:complexType name="derivedAddressType">
<xs:complexContent>
<xs:extension base="addressType">
<xs:sequence>
<xs:element name="zipCode" type="xs:token"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
<?xml version="1.0" encoding="GB2312"?>
<company xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="例8-24.xsd">
<address>
<country>中国</country>
<city>北京</city>
<street>北三环中路</street>
</address>
<employee>
<name/>
<homeAddress xsi:type="derivedAddressType">
<country>中国</country>
<city>北京</city>
<street>清华东路</street>
<zipCode>100086</zipCode>
</homeAddress>
</employee>
</company>
上面实例文档可以安全通过验证,但如果将address元素也加上属性xsi:type="derivedAddressType"时,则就不能通过验证,因为在模式文档中声明address元素时加上了block="extension"属性,所以阻止了该元素类型的扩展派生类型来替换原来的类型。
一致性约束
unique约束
确保某些元素或属性的值在某个特定的范围内是唯一的,它使用xs:unique元素来定义,其name属性指定约束名称。在xs:unique元素内部,必须按顺序包含下列元素:
l xs:selector元素:有一个必需的属性xpath,用于选择一个元素集,在其中由xs:field元素指定的值必须是唯一的。该元素必须且只能使用一次。
l xs:field元素:也有一个必须的属性xpath,其值为Xpath表达式,用于指定对于由xs:selector元素所选择的元素而言必须是唯一的值(元素或属性的值)。可以使用多个,如果使用了多个xs:field元素,那么它们所指定的元素属性值的组合必须是唯一的。
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:comp="http://www.sunxin.org/company"
targetNamespace="http://www.sunxin.org/company"
elementFormDefault="qualified">
<xs:element name="company" type="comp:companyType">
<!--由empNumber元素的值与recordNumber属性组合起来形成唯一键-->
<xs:unique name="numberUnique">
<!--选择company元素所有子节点下的record子节点,注,一定要加上空间前缀-->
<xs:selector xpath="*/comp:record"/>
<!--指定record元素的empNumber子元素注,一定要加上空间前缀-->
<xs:field xpath="comp:empNumber"/>
<!--指定record元素的recordNumber属性-->
<xs:field xpath="@recordNumber"/>
</xs:unique>
</xs:element>
<xs:complexType name="companyType">
<xs:sequence>
<xs:element name="salaryRecords" type="comp:salRecordsType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="salRecordsType">
<xs:sequence>
<xs:element name="record" type="comp:recordType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="recordType">
<xs:sequence>
<xs:element name="empNumber" type="xs:token"/>
<xs:element name="month" type="xs:positiveInteger"/>
<xs:element name="salary" type="xs:decimal"/>
</xs:sequence>
<xs:attribute name="recordNumber" type="xs:token"/>
</xs:complexType>
</xs:schema>
注,由于Xpath不支持默认名称空间,所以“xmlns ="http://www.sunxin.org/company"”需加上名称前缀“xmlns:comp="http://www.sunxin.org/company"”,而且在xpath属性的元素前需带上名称前缀,否则约束将不起作用:
<?xml version="1.0" encoding="UTF-8"?>
<company xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sunxin.org/company 例9-3.xsd"
xmlns="http://www.sunxin.org/company">
<salaryRecords>
<record recordNumber="r-001">
<empNumber>e-001</empNumber>
<month>1</month>
<salary>3500.50</salary>
</record>
<record recordNumber="r-002">
<!-- empNumber元素的值可以有重复的,但它与recordNumber
属性值的组合不能有重复的。-->
<empNumber>e-001</empNumber>
<month>2</month>
<salary>4000</salary>
</record>
</salaryRecords>
</company>
key约束
与unique约束类似,只是key约束指定的元素或属性不能是可选的,它们在实例文档中必须存在,即使在模式文档中它们是可选的,但在实例文档中一定不能省掉。
key约束也是使用xs:selector与xs:field元素来定义的,使用与unique约束一样。
keyref约束
keyref约束必须和unique约束或者key约束一起使用,keyref约束类似数据库表外键约束,而unique约束或者key约束类似数据库表主键约束。
keyref约束使用xs:keyref元素来定义,除了name属性外,还有一个refer属性,用于引用模式文档中的unique或者key约束的名称,在该元素内部,必须按顺序包含下列子元素:
xs:selector元素、xs:field元素:其xpath属性用于指定unique或key约束中的元素或属性值的元素或属性。xxs:file元素的数目必须与它所引用的unique或key约束中的xs:field元素数据相同,顺序也要相同。
<?xml version="1.0" encoding="GB2312"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="company" type="companyType">
<xs:key name="numberKey">
<xs:selector xpath="employee"/>
<xs:field xpath="number"/>
</xs:key>
<!-- refer属性的值是xs:key元素的name属性的值 -->
<xs:keyref name="numberKeyRef" refer="numberKey">
<xs:selector xpath="employee"/>
<xs:field xpath="@manager"/>
</xs:keyref>
</xs:element>
<xs:complexType name="companyType">
<xs:sequence>
<xs:element name="employee" type="empType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="empType">
<xs:sequence>
<xs:element name="number" type="xs:token" minOccurs="0"/>
<xs:element name="name" type="xs:token"/>
</xs:sequence>
<xs:attribute name="manager" type="xs:token"/>
</xs:complexType>
</xs:schema>
<?xml version="1.0" encoding="GB2312"?>
<company xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="例9-10.xsd">
<employee>
<number>e-001</number>
<name>张三</name>
</employee>
<employee manager="e-001">
<number>e-002</number>
<name>李四</name>
</employee>
<employee manager="e-001">
<number>e-003</number>
<name>王五</name>
</employee>
</company>
注,在组合使用keyref和key约束(或unique约束)时,被keyref约束引用的key约束(或unique约束)必须在同一个元素声明中定义,或在它的一个子元素声明中定义。keyref不能引用在兄弟元素或父元素声明中定义的key。
引入其他模式文档
包含xs:include
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.sunxin.org/emp"
targetNamespace="http://www.sunxin.org/emp">
<xs:complexType name="addressType">
<xs:sequence>
<xs:element name="city" type="xs:token"/>
<xs:element name="street" type="xs:token"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:emp="http://www.sunxin.org/emp"
targetNamespace="http://www.sunxin.org/emp">
<!--xs:include元素只能作为xs:schema元素的子元素,且必须
出现在模式文档的开始处,在它之前可以有 xs:redefine 与
xs:import-->
<xs:include schemaLocation="例10-1(address).xsd"/>
<xs:element name="employee" type="emp:empType"/>
<xs:complexType name="empType">
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:element name="homeAddress" type="emp:addressType"/>
</xs:sequence>
<xs:attribute name="number" type="xs:token"/>
</xs:complexType>
</xs:schema>
使用包含的一个很重要的条件就是,被包含组件的目标名称空间必须和包含方的止标名称空间一样。实际上,被包含的模式文档也可以没有名称空间,将使用包含方的目标名称空间。如果包含方也没有目标名称空间,那么就和没有使用名称空间是一样的。
如果被包含模式文档中没有定义目标名称空间,而包含方包含了目标名称空间,在被包含模式文档中,类型引用、元素引用、组引用时都直接引用,因为被包含模式文档中没有名称空间,这是可以的,当它引入到包含方模式文档里后,虽然被包含模式文档已处理包含方定义的目标名称空间中了,但解析器还是可以处理。
可以使用xs:include元素包含多个模式文档,只不过它们的目标名称空间一要样,或者被包含的模式文档中都没有目标名称空间。
重定义xs:redefine
重定义与包含类型,也可引入其他模式文档,且都要求被引入的模式文档与包含方具有相同的名称空间(或者没有目标名称空间),不同的是重定义可以对引入的模式文档中的组件进行重新定义。
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="addressType">
<xs:sequence>
<xs:element name="city" type="xs:token"/>
<xs:element name="street" type="xs:token"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:emp="http://www.sunxin.org/emp"
targetNamespace="http://www.sunxin.org/emp">
<xs:redefine schemaLocation="例10-4(address).xsd">
<!--重定义addressType组件-->
<xs:complexType name="addressType">
<xs:complexContent>
<xs:extension base="emp:addressType">
<xs:sequence>
<xs:element name="zipcode" type="xs:token"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:redefine>
<xs:element name="employee" type="emp:empType"/>
<xs:complexType name="empType">
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:element name="homeAddress" type="emp:addressType"/>
</xs:sequence>
<xs:attribute name="number" type="xs:token"/>
</xs:complexType>
</xs:schema>
注,只有简单类型、复杂类型、元素组和属性组可以被重定义。只有需要重定义的组件才应该出现在xs:redefine元素中,其他组件将被直接包含到新的模式中。
导入xs:import
导入与包含的区别是,导入发生在不同的名称空间之间,被导入的模式文档和导入方必须具有不同的名称空间。
--address.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.sunxin.org/address"
targetNamespace="http://www.sunxin.org/address">
<xs:complexType name="addressType">
<xs:sequence>
<xs:element name="city" type="xs:token"/>
<xs:element name="street" type="xs:token"/>
</xs:sequence>
</xs:complexType>
</xs:schema>
--employee.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.sunxin.org/emp"
xmlns:addr="http://www.sunxin.org/address"
targetNamespace="http://www.sunxin.org/emp">
<xs:import namespace="http://www.sunxin.org/address"
schemaLocation="address.xsd"/>
<xs:element name="employee" type="empType"/>
<xs:complexType name="empType">
<xs:sequence>
<xs:element name="name" type="xs:token"/>
<xs:element name="homeAddress" type="addr:addressType"/>
</xs:sequence>
<xs:attribute name="number" type="xs:token"/>
</xs:complexType>
</xs:schema>
如果address.xsd没有声明目标名称空间,那么xs:import元素就不能使用namespace属性,这将导入不在任何名称空间中的组件。在这种情况下,应该将employee.xsd中的type="addr:addressType"改为type="addressType",然而,在本例中,这将出现模式验证错误。这是因为employee.xsd声明了默认的名称空间xmlns="http://www.sunxin.org/emp",type="addressType"将导致引用默认名称空间中的addressType类型,但默认名称空间中并没有定义这个类型,因此出现错误。要避免这个问题,一种方式是将xmlns=http://www.sunxin.org/emp名称空间绑定到一个前缀上,另一种方式是在声明homeAddress元素的xs:element元素上设置 xmlns=""。