5.1 Schema概述
XML Schema是2001年5月正式发布的W3C的推荐标准,经过数年的大范围讨论和开发如今终究尘埃落定,成为全球公认的XML环境下首选的数据建模工具。
使用DTD虽然带来较大的方便,但是,DTD存在1些缺点:1是它用不同于XML的语言编写,需要不同的分析器技术。这增加了工具开发商的负担,下降了软件瘦身的可能性,另外开发人员需要多学1门语言及其语法。而XML Schema是按标准XML规则编写的,更容易掌握。2是DTD不支持名称空间。随着大部份的数据处理日趋以XML为中心,信息的相互联系变得日趋普及与深入,名称空间作用也将凸现。3是DTD在支持继承和子类方面的局限性。由于面向对象技术的出现,对继承和子类的支持已成为软件技术领域的主流概念。最后,DTD没有数据类型的概念,没法对特定元素施加数据类型,对强迫性结构化无计可施,例如,如何规定名为Date的数据必须包括有效值。
这些就要依托XML Schema了。XML Schema不但可以定义XML文档的结构而且还允许束缚文档的内容,这不同于DTD。另外,1个 XML Schema本身就是1个XML文档,其基于标签的语法比DTD中的特殊字符要清楚多了。XML Schema正是针对这些DTD的缺点而设计的,它完全使用XML作为描写手段,具有很强的描写能力、扩大能力和处理保护能力。
XML Schema是用1套预先规定的XML元素和属性创建的,这些元素和属性定义了文档的结构和内容模式。
XML Schema也是Web Services技术中需要使用的1个基本工具,但是其实不是XML Schema的所有特性都会被广泛地使用,因此,本书将不对XML Schema规范做系统的介绍。目前主要有两种重要的模式:Microsoft XML Schema和W3C XML Schema,本章主要讨论W3C XML Schema。
在下面的例子中,通过使用出现在Schema元素中的名称空间声明xmlns:xsd= “http://www.w3.org/2001/XMLSchema”,使得模式文档中的每个元素都有1个与XML Schema名称空间相干联的名称空间前缀xsd。虽然在语法上,可使用任意的前缀情势,但是,名称空间前缀xsd被约定用于表示XML Schema名称空间。由于使用一样的前缀,所以一样的关联就会出现在内置的简单类型的名字中,例如xsd:string。这类情势关联的目的是用来表示当前的元素或简单类型属于XML
Schema语言的内置定义,而不属于模式文档作者自己的辞汇表。为了在这里清楚并且简单地表示,仅提及元素的名字和简单类型名,而疏忽它们的前缀xsd。
5.2 Schema的格式和使用
1个XSDL(XML Schema Definition Language)文档由元素、属性、名称空间和XML文档中的其他结点构成,并且最少要包括:schema根元素、XML模式名称空间的定义和元素定义。
5.2.1 简单实例
【例5.1】 关于书籍信息的XML文档,代码如源程序code5_1.xml所示。
3国演义
罗贯中
80.00
滚滚长江东逝水,浪花淘尽英雄。是非成败转头空。青山照旧在,几度夕阳红。白发渔樵江渚上,惯看秋月春风。1壶浊酒喜相逢。古今多少事,都付笑谈中。
经典好书
文艺出版社
1998.10
如何写这个XML文档的Schema呢?可以简单地依照它的结构来定义它的每一个元素。首先加入1个xsd:schema元素。
每一个Schema文档都是从schema元素开始,并且只能有1个,用以控制Schema所使用的名称空间和另外几个选项,现在的Schema标准有好几种,这里决定它所采取的标准,因此是非常重要的。
对应着XML文档的book元素,一样也定义1个名为book的元素(element)。由于这个元素有属性(attributes)和非文本的子元素(non-text children),所以认为它是1个复杂类型(complexType)。而对简单类型,只能有值,不能有子元素或属性。同时还注意到book元素下的子元素,都依照1定的顺序排列,因此使用顺序元素(sequence element)来描写。
顺序元素(sequence element)是1个定义子元素排列顺序的元素,在下面的章节,还将介绍其他类似的元素,如选择(choice)和全选(all)。
接着定义title和author,都是xsd:string类型的简单元素,由于没有属性(attributes)或子元素。xsd:string是1个已在名域中预定义了的XML Schema类型中的1个。
接着,来处理publish元素,它也是1个复杂类型,注意它的基数的定义。
同其他Schema定义语言不1样,W3C XML Schema允许定义1个元素的使用基数,能指定元素的minOccurs(最小数)和maxOccurs(最大数)。这里设置maxOccurs为unbounded,这意味着能有任意多的publish元素。这两个属性的默许值都是1。下面,用一样的方法定义其他的子元素。
下面封闭complexType和element等元素。
这样publish元素就完成了,然后封闭book的sequence元素。
现在,声明book元素的属性,通常是在最后这么做。这样做没有甚么特别的缘由,只不过W3C XML Schema工作组认为在元素后定义属性感觉更加自然。
最后,封闭所有剩下的元素。
至此,1个Schema已完成了。其中,最关键的在于根据文档的上下关系来定义每个元素和属性,并且允许有多个同名元素带有不同的内容。为了这个目的,W3C XML Schema被设计成1种有作用域的语言,它的每个定义只能被它定义的子元素所看见。
【例5.2】 关于books.xml模式定义的完全例子,代码如源程序code5_2.xsd所示。
5.2.2 Schema的使用
符合某个模式的文档称为实例。实例可以根据特定的模式进行验证。需要声明XML文档的Schema实例名称空间(xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”),并把名称空间映照到前缀xsi。实例与模式之间有多对多的关系。1个模式可以描写多个有效的实例(通过使用不同的根元素类型来实现),一样,1个实例也能够被多个模式描写。例如1个实例可能具有多个模式,它们有不同的验证级别。其中1个模式可能只验证结构,而另外一个模式则根据数据类型来检查每个数据项。
1. Schema的作用
Schema文档用来验证XML文档的正确性,用来判断实例是不是符合模式中所描写的所有束缚,触及到检查实例中所有的元素和属性。
Schema主要检验以下内容:
(1) 验证数据的显示格式是不是正确及是不是超越值的范围;
(2) 验证所有必须的信息都存在;
(3) 确保不同使用者对文档理解的方式相同。
除对XML文档的验证外,Schema文档还在1定程度上扩充实例:
(1) 为元素和属性添加默许值和固定值;
(2) 使具有简单类型的元素和属性值中的空白符规范化。
targetNamespace=”http://example.org/ord”>
要验证XML文档,必须指定Schema文档的位置。模式的位置可以利用带着名称空间模式的xsi:schemaLocation属性和不带名称空间XML模式的xsi:noNamespace SchemaLocation 属性来指定,它们位于根/顶级元素中或XML文档的任何其他元素中。
当Schema文档不包括targetNamespace属性时,应当通过XML文档根元素的noNamespace SchemaLocation属性及W3C的Schema实例名称空间(xmlns:xsi=“http://www.w3.org /2001/XML Scheam-instance”)来援用XML Schema文件。针对上面的实例修改以下:
isbn=”0⑺64⑸8007⑻”>
但是,如果Schema文档包括了1个targetNamespace 属性,在XML文档中就将通过schemaLocation属性而不是noNamespaceSchemaLocation属性来援用Schema文档。而且,这个属性所指定的值必须是完全的。它需要包括以空格分开的两部份,前1部份是URI,这个URI与Schema文档的targetNamespace属性内部援用的URI是1致的;后1部份是Schema文件的完全路径及名称。另外,XML文档的根元素也必须声明Schema实例名称空间(xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”)。Schema文档以下所示:
则修改上面的实例为
xmlns=”http://tempuri.org/book”
isbn=”0⑺64⑸8007⑻”>
元素是创建XML文档的主要构建材料。在W3C XML Schema中,元素通过使用element元素实现。元素声明用于给元素指定元素类型名称、内容和数据类型等属性。在XSDL中,元素声明可以是全局的,也能够是局部的。
5.3.1 schema根元素
在schema文档中必须定义1个且只能定义1个schema根元素。根元素不但表明了文档类型,而且还包括模式的束缚、XML模式名称空间的定义,其他名称空间的定义、版本信息、语言信息和其他1些属性。定义以下:
…
其中name属性指定Schema名称,也能够不需要。xmlns指定所属名称空间,紧跟在后面的xsd则是该名称空间的名称,名称空间http://www.w3.org/2001/XMLSchema被映照到xsd前缀,在后面将详细说明名称空间。
5.3.2 element元素
XSD中的元素是利用element来声明的。其中name属性是元素的名字,type属性是元素值的类型,在这里可以是XML Schema中内置的数据类型或其他类型。具体定义格式以下:
name是元素类型的名称,必须是以字母或下划线开头,而且只能够包括字母、数字、下划线、连接符及句号。type属性是必要的,说明元素的数据类型。
下面的例子定义全局元素声明author,为简单字符串类型。
与以上文档对应的有效XML文档以下:
罗贯中
在元素的定义中还有两个属性:minOccurs和maxOccurs。其中minOccurs定义了该元素在父元素中出现的最少次数(默许为1,值为大于等于0的整数),maxOccurs定义了该元素在父元素中出现的最屡次数(默许为1,值为大于等于0的整数)。在maxOccurs中可以把值设置为unbounded,表示对元素出现的最屡次数没有限制。
表示元素author的类型为string,出现的次数最少为0(就是可选),最多不限制。
1般来讲,如果元素声明出现在Schema文档的顶级结构中,也就是说,它的父元素是schema,那末这些元素为全局元素。
相反,局部元素声明只出现在复杂类型定义的内部,局部元素声明只在该类型定义中使用,而不被其他复杂类型援用或在替换组中使用。不同的复杂类型,可以有相同元素类型名称的局部元素。
【例5.4】 显示title、author和price3种局部元素声明的模式文档,代码如源程序code5_4.xsd所示。
5.3.3 设置默许值和固定值
默许值和固定值通过给空元素增加值的方式来扩大实例。如果文档中存在空的元素,模式处理器根据模式文档的定义,会插入默许值或固定值。在XSDL中,默许值和固定值分别通过default和fixed属性设置。两个属性只能出现其中之1,由于它们是互斥的。
如果元素为空,就填入默许值。下例中,声明了city元素,并指定了默许值为“佚名”。
必须注意的是,元素声明中“空”的定义根据数据类型不同而有所不同。某些数据类型允许空值,包括string等。任何允许空字符串值的类型,元素都不会认为是空的,从而对字符串类型元素,默许值不会被填充。相反,integer数据类型的空元素通常会被认为是空的,从而将填入默许值。另外,如果元素的xsi:nil属性被设置为true,那末就不会插入它的默许值。
元素的默许值行动见表5⑴。
表5⑴ 元素的默许值行动
情 况 填充实例结果 填充之前 填充以后
指定值 保持原始值罗贯中罗贯中
空元素(integer) 填充值30
空元素(string) 没有填充值
元素为空 没有填充值
固定值与默许值在相同的情况下添加,它们的差别仅在于如果元素具有1个值,则该值必须和固定值相等。当模式解析器肯定元素值和固定值实际上是不是相等时,会斟酌到元素的数据类型。price元素的数据类型为integer,所以整数1的所有情势在实例中都会被接受,包括01、+1和周围包括空白符的1。相反,对author元素具有数据类型为string,字符串“01”是无效的,由于与字符串“1”其实不相等。
依照以上定义,元素的固定值行动见表5⑵。
表5⑵ 元素的固定值行动
有效实例 无效实例
12
0101
+1+1
1
5.3.4 援用元素和替换
援用是利用element元素的ref属性实现的。主要适用于避免在文档中屡次定义同1个元素,应当将常常使用的元素定义为根元素的子元素,即为全局元素,这样方便在文档的任何地方援用它。如每本书籍都有作者,其他产品也会有作者,因此可以把author属性声明为全局元素,供文档中多处援用。
【例5.5】 援用元素定义的模式文档,代码如源程序code5_5.xsd所示。
在这里还可以为某个定义的元素起1个别名,主要是利用element元素中的substitutionGroup属性实现的。
方法以下:
以上文档对应的有效XML文档以下:
罗贯中
或:
string
属性声明用于命名属性并使之与某个特定的简单类型相干联。在XSDL中,实现的方法是使用attribute元素。在XML Schema文档中可以依照定义元素的方法定义属性,但受限制的程度较高。它们只能是简单类型,只能包括文本,且没有子属性。属性是没有顺序的,而元素是有顺序的。
使用属性10分简练,元素的功能比属性强大,但在某些场合属性是非常有用的。通常,对元数据使用属性,而对数据则使用元素。如用属性描写单位、语言或元素值的时间相依性。
5.4.1 创建属性
定义属性的方法以下:
该语句定义了1个名为isbn的属性,它的值必须是1个字符类型。
属性也分全局和局部属性。全局声明的属性是schema元素的子元素,在模式文档中必须是唯1的。复杂类型的元素,使用ref属性通过名称来援用属性。局部属性声明只出现在复杂类型定义中,它们仅能在类型定义中使用,而不能被其他类型重用。下面的例子显示了两个属性——isbn和amount 的全局声明,然后定义了1个复杂类型,使用ref属性通过名称来援用这两个属性。
use属性用于唆使属性是必须的还是可选的,它出现在属性援用而不是属性声明中,由于它关系到属性在复杂类型中的出现,而不是属性本身。上面的例子定义的是全局的属性定义方式,如果要在复杂类型里声明属性,可以参照下面的例子:
rbut
上面的例子描写了isbn和amount两个属性的局部声明,它们完全出现在复杂类型的定义中。局部声明的属性名称,作用范围仅限于复杂类型内,在同1个复杂类型定义中,两个属性使用相同的限定名称是非法的。只有当属性会被多个名称空间的多个元素声明使用到时,才提倡将该属性声明为全局属性。
5.4.2 为属性指派类型
所有的属性声明都把属性指定为某种简单类型。所有的属性都具有简单类型而不是复杂类型,由于它们本身不能有子元素和属性。
属性声明有3种方式:
(1) 在属性声明中通过用type属性指定命名简单类型。它可以是内置类型,也能够是用户自定义类型。
(2) 通过指定simpleType子属性来指定匿名类型。
(3) 既没有type属性,又没有simpleType子属性,从而不指定特定类型。在这类情况下,属性的类型为anySimpleType,它可以具有任何值,只有它是结构公道的XML文档。
下例显示4个属性的声明,采取了不同的类型指定方法。定义了grade属性并赋予gradeType类型,amount属性指定了内置类型integer,同时使用内嵌的匿名简单类型来声明bookcategory属性,anything属性没有指定特定的类型。
5.4.3 属性的默许值和固定值
对属性来讲,也能够通过默许值和固定值的方式增加未出现的属性来扩充实例。定义和扩充的方式与元素1致。在XSDL中,默许值和固定值分别通过default和fixed属性设置。两个属性只能出现其中之1,由于它们是互斥的。
如果属性在元素中默许,它的默许值将会被填入。如果属性出现,且包括任意值,它将保持该值不变。下面的例子显示了book元素的声明,它包括1个amount属性,该属性被指定了默许值。
固定值与默许值在基本1样的情况下被插入,区分在于,其值应和固定值相等。同时也会斟酌属性的类型。
W3C XML Schema可以把XML文档中的元素声明为特定的类型,准予解析器检查文档的内容及其结构。XML Schema定义了两种主要的数据类型:预定义简单类型和复杂类型。这两种数据类型之间的主要区分是复杂类型可以像数据1样包括其他元素而简单类型则只能包括数据。简单类型给予了XML Schema低级类型检查能力。
5.5.1 简单类型
元素和属性声明都可使用简单类型来描写数据类型。
1. 简单类型的种类
原子类型(不可分割的类型,如string、integer等系统内建的类型)、列表类型、联合类型合起来统1称为简单类型。XML Schema具有低级类型检查能力,允许把元素定义为表5⑶中的任何类型之1。赋予简单类型的元素具有字符类型内容,但没有子元素或属性。
(1) 原子类型具有不可分割的值,如10和large。
(2) 列表类型的值为用空格符隔开的原子值列表,如10 large 2
(3) 联合类型的值可以是原子值,也能够是列表值。它们的区分在于该类型的有效值集是两个或多个其他简单类型值空间的联合。如要对学生的成绩评定等级,可以定义1个联合类型,它允许的值既可以是0~100的整数,也能够是优、良、合格或不合格。
表5⑶ XML Schema支持的部份简单类型
内建类型 定 义
string 字符串数据,如”online book shop”
boolean 2元类型的true或false
date 表示日期,格式是ccyy-mm-dd
dateTime 表示当前时间,由日期和时间组成,如11/18/80,10:00am
time 24小时格式的时间可根据时区调理
decimal 任意精度和位数的10进制数,如27.93
integer 整数,如34
float 标准的32位浮点数,如11.87e⑵
在前面1些例子中,有几个元素和属性被声明为简单类型。其中1些简单类型如 string 和integer是XML Schema中内置的类型,其他的1些则是源于(如果使用对象技术的语言就是继承)内置的类型。
除此以外,新的简单类型可以通过从现有的简单类型(内置的简单类型和源于内置简单类型的简单类型)引出定义。通常,通太重新束缚1个现有的简单类型来引出1个新的简单类型。换句话说,新类型的合法值范围是现有类型的值范围的子集。使用simpleType元夙来定义和命名新的简单类型,使用restriction元夙来指出现有的基类型,并且用它来标识束缚值范围的细节。
假定希望建立1个新的整数类型称为myInteger,它的值范围为10000~99999。那末定义应当基于简单类型integer,然后定义它的值范围为10000~99999。为了定义myInteger,这样来束缚integer的范围,示例以下:
这个例子显示了由1个基本类型定义和两个值域区间方面描写的组合,通过这3个要素对myInteger实行定义。
2. 简单类型的命名定义
简单类型既可以为命名简单类型又可以为匿名简单类型。命名简单类型总是在全局定义的,而且要求在模式的数据类型中具有唯1名称。类型的名称必须为XML无冒号名称,即必须以字母或下划线开始,只能包括字、数字母、下划线、连字符和句点。如上面的例子,简单类型名为myInteger。
这类类型的模式构造非常直接了当,但有些不实用。特别是如果定义了许多只利用1次而且包括非常少束缚的类型,在这类情况下,1个类型应当能够被更简单的定义。这样的简单定义通常的情势是1个省略了名称和外部援用开消的匿名类型。
在下面的示例中,publish元素声明使用了匿名类型定义。1般来讲,通过元素中是不是包括“type=”这个属性可以判断匿名属性定义(或是匿名元素定义)。如果出现无名称的类型定义,也能够认为是匿名属性(元素)定义。
3. 简单类型的限制
每一个简单类型都是从另外一个简单类型派生而来的,则另外一个简单类型称为基类型。可以从原子类型,也能够从用户定义的简单类型派生。上面的例子都从内置的原子类型派生成新的简单类型。所有新的简单类型都以某种方式限制其基类型的值空间。下面的例子从简单类型种类例子中定义的myInteger类型进1步限制。
简单类型定义时,都是通过restriction元夙来定义限制,通过base属性来规定1种基类型。在restriction内,可以任何顺序指定任何面(facet),来对类型取值进1步限制。根据面的不同,这个元素或属性具有不同的有效值。XML Schema面的定义见表5⑷。
表5⑷ XML Schema面的定义
面 意 义
minExclusive 值必须大于x,相对就有maxExclusive
minInclusive 值必须大于等于x,相对就有maxInclusive
length 值的长度必须等于x
minLength 值的长度必须大于等于x,相对就有maxLength
totalDigits 有效数字的位数必须小于等于x
fractionDigits 小数位数必须小于等于x
whiteSpace 是不是保存、替换或紧缩whitespace,决定于x
enumeration x是1个有效值
pattern x是值可以匹配1个正则表达式
对每一个内置的原子类型来讲,都有1套定义时可用的面。如果某个面适用于某种原子类型,那末也适用于由该类型派生的简单类型。这里有必要举例说明枚举的简单类型定义,下面的例子定义了1个简单类型category,用于说明书籍的种别。
20003 15037 95977 95945
1些用于描写的参数能够被利用到列表类型的定义中,它们是length、minLength、maxLength和enumeration。举例来讲,如果想定义1个列表类型,这个列表类型正好包括了6个分类项名。首先从category类型定义1个新的列表类型,称为cateList,然后通过限制cateList导出只有3个项的threeBookCate类型。具体的定义以下:
小说 散文 传记
类型为threeBookCate的元素必须有3个项,它们中的每个项必须是1个枚举类型category的原子类型(枚举类型将在后面的章节中介绍),在示例后半部份的实例文档中就是1个具体的利用例子。
需要注意的是,从原子类型string可以导出1个列表类型,但是,在1个string中或许会带有空格,而空格在1个列表类型实例中是作为分隔符使用的,因此当在使用基类型为string的列表类型时,应当格外谨慎。举例来讲,假定定义了1个length取值为3的列表类型,同时这个列表类型基于类型string。下面由3个元素这样组成的列表是合法的Asia Europe Africa;而由3个元素这样组成的列表是不合法的Asia Europe Latin America。即便Latin America在列表外可以作为单独的1个字符串存在,但当它包括在列表中时,在Latin和America之间的空格使得第4个项被有效地生成了,因尔后面的例子不符合只有3个项的列表类型定义。
5. 联合类型
利用原子类型和列表类型,1个元素或属性的值可以为1个或多个原子类型(列表类型)的实例。与之相比较,1个联合类型(Union Type)包括了多个原子类型或列表类型,而利用了联合类型的元素或属性,它们的值可以是联合类型中所包括的这些原子类型或列表类型中的任何1个类型实例。为了说明这1点,建立1个用于表示学生成绩的由评定等级或数字列表的联合类型。gradeUnion联合类型由1个原子类型和1个列表类型构成。
组成联合类型的简单类型称为它的成员类型。成员类型必须是简单类型,不存在复杂类型的联合。除直接用简单类型来规定成员类型外,还可使用union元素的memberTypes属性来规定成员类型。假定已在模式文档的其他地方定义了gradeType和scoreInteger,改写上面的例子:
87
优
当在定义1个联合类型时,union元素的memberTypes属性的值包括了联合类型中所有类型的列表。现在,假定声明了1个gradeUnion类型的元素,称为stuScore,stuScore元素有效的实例可参见上面的实例。
另外,对联合类型而言,还有两个描写性质的参数pattern和enumeration也能够应需要使用。
5.5.2 复杂类型
复杂类型的元素具有子元素和属性,还可以有字符内容。复杂类型和简单类型之间最根本的区分就是:复杂类型的内容中可以包括其他元素或属性,但简单类型既不能包括子元素,也不能带有任何属性。复杂类型有4种不同的内容类型:简单类型、纯元素类型、混合类型及空类型。下例中给出了具有复杂类型的元素:book是带有属性的元素、bookinfo是包括子元素的纯元素复杂类型、chapter是混合类型的复杂类型元素和内容为空的元素price。它们分别属于下面要描写的4种不同的内容类型。
no.1
3国演义
罗贯中
宴桃园豪杰3结义 斩黄巾英雄首立功
话说天下大势,分久必合,合久必分。
复杂类型由complexType元素创建,同简单类型1样,复杂类型可以是命名的,也能够是匿名的。命名的复杂类型可以被多个元素声明使用,1般在全局范围内定义。相反,匿名的复杂类型完全在元素声明中进行定义,而且只可以被该声明使用1次。有3种不同的方法:
(1) 单个complexContent子元素,可使用它从1个复杂类型派生出新的复杂类型;
(2) 单个simpleContent子元素,用于从简单类型派生出复杂类型;
(3) 组(group、all、choice或sequence)加属性,用于定义1种非派生于特定类型的复杂类型。
1. 内容类型
所谓元素的内容是在标记之间的字符数据和子元素。复杂类型子元素的顺序和结构称为它的“内容模型”。复杂类型的内容类型有4种:简单内容、纯元素内容、混合内容和空内容。内容类型不依赖于属性,所有这些内容类型都允许有属性。
简单内容只允许有字符数据,它没有子元素。1般说来,简单类型和具有简单内容的复杂类型的唯1区分在于后者可以有属性,以下面的book元素。
no.1
要定义如上所示的book元素,必须按以下方法定义。复杂类型bookType的字符数据内容符合简单类型string,而且还添加了isbn属性。
纯元素内容只允许有子元素,而没有字符数据内容。下例显示了具有纯元素内容的bookinfo元素,它有两个子元素:title和author。
3国演义
罗贯中
可以按以下方式进行定义:
混合内容既允许有字符数据又允许有子元素。常常用于字母和文档等情势的自由文本。下例中显示了具有混合内容的chapter元素。chapter元素中直接包括字符数据和子元素para。
宴桃园豪杰3结义 斩黄巾英雄首立功
话说天下大势,分久必合,合久必分。
在创建所示的chapter元素类型定义时,需要设置complexType的mixed属性为true,允许有字符数据内容。mixed的默许值为false。
空内容既不允许有字符数据也不允许有子元素。带有空内容的元素通常在属性中具有值。有某些情况下,乃至可以没有属性,但空内容的元素存在本身就成心义。如XHTML中的
元素就表示1个新行。
要定义空内容元素的类型时,只需指定属性,不用做其他内容的说明。
2. 利用组合器控制结构
模式组允许把子元素声明或援用组合起来,从而构建更成心义的内容模型。模式组共有3种:sequence、choice和all。
sequence组合器,定义了1列元素并且必须依照模式中指定的顺序显示,所有子元素。如果出现的话,都必须依照该顺序出现。示例以下。
下面显示了1些book的有效实例。它的子元素都以正确的顺序出现。
3国演义
罗贯中
文艺出版社
choice组合器用来声明只有1个相容元素必须出现,用于互斥情况。示例以下。
下面的实例都是有效的,每个实例包括1个符合choice组中声明的子元素。如果出现多个子元素,或根本没有任何元素出现,那末该实例将是无效的。
3国演义
罗贯中
choice组合器还可以允许任意数量的子元素以任意顺序出现。只要通过把choice组的maxOccurs属性设置为unbounded便可允许子元素以任何顺序出现,出现任意次数。另外,为了指定更加高级的内容,sequence和choice可以彼此嵌套,可以进行任意层数的嵌套。
all组合器用来表示符合元素声明的所有元素都应当出现(以任何顺序)且只能出现1次。all组合器与choice和sequence的不同的地方在于:
(1) 只能包括元素声明和援用,而不能包括其他组。
(2) 不能出现屡次。对所包括的每一个子元素,maxOccurs必须为1,而minOccurs只可以为0或1。不能出现在其他模式组中。all组必须在复杂类型的最高层。
示例以下。
根据上面的定义,下面显示了book的两个有效实例。price和publisher元素定义了minOccurs等于0,因此可以不出现。
3国演义
罗贯中
文艺出版社
30
3国演义
罗贯中
名称空间是XML Schema中的重要部份,它提供了1种避免元素命名冲突的方法。名称空间的用处在于为XML中使用的名称提供1个容器。
5.6.1 命名冲突
XML是可扩大的,而这类扩大不遭到控制。由于XML文档中使用的元素不是固定的,那末便可能会出现多个不同的XML文档使用同1个名字来描写不同类型的元素的情况。而这类情况又常常会致使命名冲突。请看下面两个例子。
以下XML文档在table元素中携带了水果的信息:
Apples | Bananas |
以下XML文档在table元素中携带了桌子的信息:
African Coffee Table
80
120
如果上面两个XML文档片断碰巧在1起使用的话,那末将会出现命名冲突的情况。由于这两个片断都包括了table元素,而这两个table元素的定义与所包括的内容又各不相同。
5.6.2 使用前缀解决命名冲突问题
前面的例子中所出现的命名冲突问题就是由于XML的可扩大性致使的,没有办法能够避免任何人以与其他人不兼容的方式对文档进行扩大。名称空间的出现就是为了解决这个问题的。名称空间定义了1个标记的容器,为所有在文档中使用的标记名称提供语境。实例文档中的元素类型或属性的名称可能直接与名称空间关联,或就属于某个名称空间。这样就能够避免命名的冲突。因此,可以这样改造上面的XML文档,在table元素前面加上前缀。
Apples
Bananas
则家具table的信息变成:
African Coffee Table
80
120
现在已没有元素命名冲突的问题了,由于这两个文档对各自的table元素使用了不同的前缀,table元素在两个文档中分别是和。但是,前缀还不能完全解决问题,由于任何人都可以创建前缀,如果两个文档创建了相同的前缀,则又出现冲突问题。为了不前缀冲突,可使用以下的前缀声明。
f=”http://www.example.org/html”
h=”http://www.example.org/furniture”
将统1资源标识符(Uniform Resource Identifier,URI)跟前缀联系起来。由于URI跟标记或前缀不同,它具有唯1性。这就是名称空间的解决方法。
5.6.3 使用名称空间
名称空间属性1般放置在元素的开始标记处,从xmlns属性开始,后面是前缀。其使用语法格式以下:
xmlns:namespace-prefix=”namespace”
具体示例以下:
xmlns:f=”http://www.w3.org/2000/10/XMLSchema”
前缀只是起着名称空间的代理作用。名称空间的名称是URI,而不是前缀,在比较两个元素时,解析器是根据URI来辨认它们的名称空间,而不是根据前缀辨认。上面的例子则可以与不同的名称空间关联到1起。
Apples
Bananas
下面是携带了家具table的信息XML文档。
African Coffee Table
80
120
5.6.4 URI、URL和URN
名称空间的声明将1个全局名称(URI)跟元素的名称联系在1起。URI只作为标识符。仅就作为XML名称空间来讲,URI没必要是有效的。也就是说,它没必要指向任何位置。XML名称空间只将它们作为字符串处理。比较是逐一字符进行的,因此,下面的两个URI是不同的,虽然指向同1个文档。
http://www.example.org
http://example.org
而且名称空间是辨别大小写的。即便唯一大小写区分,也会被解析为不同的URI。
大多数的URI都是URL或Internet地址。可能指向网络上的某个文件、用户电子邮箱(mailto:branch@example.org)或是新闻组(news:comp.exmaple.xml)。
目前正在开发另外一种情势的URI,称为URN(Uniform Resource Name)。二者的区分在于:对地址来讲,如果文档移动了位置,那末地址就失效了,而URN不是地址,它们与文档的位置无关。URN是用“urn:”前缀构建的,后跟1个前缀表明该URN的类型,最后是值。
urn:isbn: 0⑺64⑸8007⑻
这里ISBN的编号就是URN的实例。每一个ISBN编号都代表了1本书。
5.6.5 名称空间的作用域
名称空间声明可以出现在文档的任何开始标记中,它的作用域是它在其开始标记中出现的元素和其所有子元素等。
3国演义
罗贯中
80.00
经典好书
文艺出版社
1998.10
上面的示例中声明了两个名称空间,bk是顶层元素声明的,因此对所有元素都是有效的。ph是为publisher元素声明的,只对它的子元素有效。但是,如果还有1个book元素,它的子元素publisher使用了ph前缀,则是不合法的名称空间,由于超越了其作用域。1般来讲,最好把所着名称空间声明都放到根元素的开始标记中。这样可以1下子看到文档的所着名称空间,对它们的作用域也不会混淆。
5.6.6 在XSDL中使用的名称空间
1. 目标名称空间
每个XSDL模式文档都可以是1个名称空间,这称为它的目标名称空间(Target Namespace)。每一个被全局声明所声明和定义的元素、属性、类型或组等都与该目标名称空间有关。下例中声明了http://www.example.org/2005/book的目标名称空间。
targetNamespace=”http://www.example.org/2005/book”>
而下面的例子显示相应的元素如何出现在1个实例中。
3国演义
罗贯中
80.00
2. XML Schema名称空间
由于XSDL也是XML文档,所以名称空间也适用于它。在XSDL中使用的所有元素:schema、element和simpleType,都在XML Schema名称空间中,其名称空间名称为http://www.w3.org/ 2001/XMLSchema。另外,内置的简单类型也在这个名称空间中。最常映照到这个名称空间的前缀是xsd或xs。如上面的例子,都采取xsd前缀。
3. XML Schema实例名称空间
XML Schema实例名称空间是实例中可以出现的4个与模式相干的属性的独扬名称空间,其名称空间名称为http://www.w3.org/2001/XMLSchema-instance,1般映照到前缀xsi。当在实例中使用这4个属性:nil、type、schemaLocation和noNamespaceSchemaLocation时,需要声明XML
Schema实例名称空间,在实例中它们的名称必须加前缀。
4. 模式文档中名称空间的声明
为了解析模式文档的援用,模式文档必须包括目标名称空间和XML Schema名称空间的声明。可以把XML Schema名称空间映照到像xsd或xs这样的前缀,从而使目标名称空间成为默许名称空间。这样由XML Schema定义就显得非常清楚了,示例以下。
targetNamespace=”http://www.example.org/2005/book”>
另外一种方法是把前缀映照到目标名称空间,并使XML Schema名称空间成为默许名称空间。下例显示了这1方法。声明中的名称本身不需要加前缀,由于它们自动成为XML Schema名称空间的1部份,唯1使用前缀的地方就是对其他组件的援用。如book元素通过限定名称援用类型BookType。如果不加前缀,那末解析器将在XML Schema名称空间中寻觅BookType的定义。
targetNamespace=”http://www.example.org/2005/book”>
有时,把前缀映照到所着名称空间也是可以的,这样全部文档也非常清晰。
targetNamespace=”http://www.example.org/2005/book”>
利用前面有关的XML文档进行简化,现在使用XML Spy来建立Schema文档。
【例5.6】 简化了的书籍XML文档,代码如源程序code5_6.xml所示。以此为例,逐渐建立Schema文档。
3国演义
罗贯中
80.00
滚滚长江东逝水,浪花淘尽英雄。是非成败转头空。青山照旧在,几度夕阳红。白发渔樵江渚上,惯看秋月春风。1壶浊酒喜相逢。古今多少事,都付笑谈中。
5.7.1 建立根结点
选择菜单File | New,弹出Create new document 对话框,选择里面的xsd(XML Schema file),这样1个空的Schema文档就会被建立,然后从Schema/WSDL视图区切换到Grid视图区,如图5.1所示。
图5.1 新建1个Schema文档
窗体下方的几个按钮提供不同的视图来设计Schema文件。本例选择的是Grid视图,可以有许多详细信息。
接着,单击左上角的黑3角,编码方式项enconding默许值为UTF⑻,将其改成GB2312,以便使用中<