1、第 5 章 XML Schema 结构 返回主页 上一章 下一章教学提示:XML schema 是 DTD(文件类型定义)之后第二代用来描述 XML 文件的标准。是用来对 XML 文档的类型定义的语言,用来规定 XML 文档的数据类型及组织方式,同时还是丰富的元数据资源。XML schema 是一种定义文件的方式,拥有许多类似 DTD 的准则,但又要比 DTD 更为强大一些。W3C 协会宣称,与 DTD 相比 XML schema 拥有许多优势。教学目标:理解 XML Schema 的含义及用途,了解 XML Schema如何为 XML 文档结构、内容和数据类型建模提供严格而完整的标准,理解
2、XML Schema 的元素、属性和类型等构件,理解 XML Schema的名称空间的概念。5.1 Schema 概述5.2 Schema 的格式和使用5.3 Schema 元素声明5.4 Schema 属性声明5.5 Schema 的数据类型5.6 Schema 的名称空间5.7 使用 XML Spy 建立 Schema 文档小 结习 题写字版 绘图板 进入 Editplus5.1 Schema 概述 本章开头 下一节XML Schema 是 2001 年 5 月正式发布的 W3C(万维网联盟)的推荐标准,经过数年的大规模讨论和开发如今终于奠定下来,成为全球公认的 XML 环境下首选的数据建
3、模工具。使用 DTD 虽然带来较大的方便,但是,DTD 存在一些缺陷:一是它是用不同于 XML 的语言编写的,需要不同的分析器技术。这增加了工具开发商的负担,削减了软件瘦身的可能性,此外开发人员需要多学一门语言及其语法。而 XML Schema 是按标准 XML 规则编写的,更容易掌握。 二是 DTD 不支持名称空间。随着计算日益以 XML 为中心,信息的相互联系变得日益普及与深入,名称空间作用也将凸现。三是 DTD在支持继承和子类方面的局限性,由于面向对象技术的出现,对继承和子类的支持已成为软件技术领域的主流概念。最后,DTD 没有数据类型的概念,无法对特定元素施加数据类型,对强制性结构化无
4、计可施,比如如何规定名为 Date 的数据必须包含有效值。这些就要依靠 XML Schema 了。XML Schema 不仅可以定义 XML 文档的结构而且还允许约束文档的内容,这就不同于 DTD 了。另外,一个 XML Schema 自身就是一个 XML 文档,其基于标签的语法比 DTD 中的特殊字符要清楚多了。XML Schema 正是针对这些 DTD 的缺点而设计的,它完全使用 XML 作为描述手段,具有很强的描述能力、扩展能力和处理维护能力。XML Schema 是用一套预先规定的 XML 元素和属性创建的,这些元素和属性定义了文档的结构和内容模式。XML Schema 也是 Web
5、Services 技术中需要使用的一个基本工具,然而并不是 XML Schema 的所有特性都会被广泛地使用,因此,将不对XML Schema 规范做系统的介绍。目前主要有两种重要的模式:Microsoft XML Schema 和 W3C XML Schema,本章主要讨论 W3C XML Schema 在下面的例子中,通过使用出现在 schema 元素中的名称空间声明xmlns:xsd= “http:/www.w3.org/ 2001/XMLSchema“,使得模式文档中的每一个元素都有一个与 XML Schema 名称空间相联名称空间前缀xsd。尽管在语法上,可以使用任意的前缀形式,但是
6、,名称空间前缀xsd 被约定用于表示 XML Schema 名称空间。由于使用同样的前缀,所以同样的关联就会出现在内置的简单类型的名字中,例如xsd:string。这种形式关联的目的是用来表示当前的元素或简单类型是属于 XML Schema 语言的内置定义的,而不是属于模式文档作者自己的词汇表的。为了在这里清楚并且简单地表示,仅提及元素的名字和简单类型名,而忽略它们的前缀 xsd。5.2 Schema 的格式和使用 上一节 下一节 本章开头一个 XSDL(XML Schema Definition Language)文档由元素、属性、名称空间和 XML 文档中的其它节点构成的,并且至少要包含:
7、schema 根元素和 XML 模式名称空间的定义、元素定义。5.2.1 简单实例【例 5.1】关于书籍信息的 XML 文档,code5_1.xml。三国演义罗贯中80.00 滚滚长江东逝水,浪花淘尽英雄。是非成败转头空:青山依旧在,几度夕阳红。白发渔樵江渚上,惯看秋月春风。一壶浊酒喜相逢:古今多少事,都付笑谈中。经典好书文艺出版社1998.10如何写这个 XML 文档的 Schema 呢?可以简单的依照它的结构来定义它的每个元素。首先加入一个 xsd:schema 元素。顺序元素(sequence element)是一个定义子元素排列顺序的元素,在下面的章节,还将其它类似的元素,如选择(ch
8、oice)和全选(all)。接着定义 title 和 author,都是 xsd:string 类型的简单元素,因为没有属性(attributes)或者子元素。xsd:string 是一个已经在名域中预定义了的 XML Schema 类型中的一个。 接着,来处理 publish 元素,它也是一个复杂类型。注意它的基数的定义。同其它 Schema 定义语言不一样,W3C XML Schema 允许定义一个元素的使用基数,能指定元素的 minOccurs(最小数)和 maxOccurs(最大数)。这里设置 maxOccurs 为 unbounded,这意味能有任意多的publish 元素。这两个属
9、性的默认值都是 1。下面,用同样的方法定义其它的子元素。下面封闭 complexType 和 element 等元素:这样 publish“元素就完成了。然后封闭 book 的 sequence 元素。现在,声明 book 元素的属性,通常是在最后这么做。这样做没有什么特别的原因,只不过 W3C XML Schema 工作组认为在元素后定义属性感觉更加自然。最后,封闭所有剩下的元素。至此,一个 Schema 已经完成了。在这其中,最关键的在于根据文档的上下关系来定义每一个元素和属性,并且允许有多个同名元素带有不同的内容。为了这个目的,W3C XML Schema 被设计成一种有作用域的语言,它
10、的每一个定义只能被它定义的子元素所看见。【例 5.2】关于 books.xml 的模式定义的完整例子,code5_2.xsd5.2.2 Schema 的使用符合某个模式的文档称为实例。实例可以根据特定的模式进行验证。需要声明 xml 文档的 schema 实例名称空间(xmlns:xsi=“http:/www.w3.org/2001/XMLSchema-instance%2522),并把名称空间映射到前缀 xsi。实例与模式之间有多对多的关系。一个模式可以描述多个有效的实例(通过使用不同的根元素类型来实现),同样,一个实例也可以被多个模式描述。例如一个实例可能拥有多个模式,它们有不同的验证级别
11、。其中一个模式可能只验证结构,而另一个模式则根据数据类型来检查每一个数据项。1. Schema 作用Schema 文档就是用来验证 XML 文档的正确性,用来判断实例是否符合模式中所描述的所有约束。涉及到检查实例中所有的元素和属性。Schema 主要检验如下内容:验证数据的显示格式正确及是否超出值的范围。 验证所有必需的信息都存在。 确保不同使用者对文档理解的方式相同 除了对 XML 文档的验证外,Schema 文档还在一定程度上扩充实例:为元素和属性添加默认值和固定值。 使具有简单类型的元素和属性值中的空白符规范化。 2. Schema 引用一个模式可能由多个模式文档构成。多个模式文档通过包
12、含或导入机制来形成模式,当其他模式文档与主模式文档具有相同的目标名称空间时,需要使用包含。当模式文档之间各自拥有不同的目标名称空间时,需要使用导入。下面的例子建立一个单独用来验证一个实例的模式文档。【例 5.3】关于多个模式文档通过包含实现定义的例子,code5_3.xsd要验证 XML 文档,必须指定 Schema 文档的位置。模式的位置可以利用带有名称空间的模式的 xsi:schemaLocation 属性以及不带名称空间的 XML 模式的 xsi:noNamespaceSchemaLocation 属性来指定,它们位于根/顶级元素中或 XML 文档的任何其他元素中。当 schema 文档
13、不包括 targetNamespace 属性时,应当通过 XML 文档根元素的 noNamespaceSchemaLocation 属性及 W3C 的 schema 实例名称空间(xmlns:xsi=“http:/www.w3.org/2001/XMLScheam-instance%2522)来引用 XML schema 文件。针对上面的示例修改如下:然而,如果 Schema 文件包含了一个 targetNamespace 属性,在XML 文档中就将通过 schemaLocation 属性而不是noNamespaceSchemaLocation 属性来引用 schema 文档。而且,这个属性所
14、指定的值必须是完整的。它需要包含以空格分开的两部分,前一部分是 URI,这个 URI 与 schema 文档的 targetNamespace 属性内部引用的 URI 是一致的;后一部分是 schema 文件完整路径及名称。另外,XML 文档的根元素也必须声明 schema 实例名称空间(xmlns:xsi=“http:/www.w3.org/2001/XMLSchema-instance%2522)。Schema 文档如下所示:则修改上面的实例为:5.3 Schema 元素声明 上一节 下一节 本章开头元素是创建 XML 文档的主要构建材料。在 W3C XML Schema 中,元素通过使用
15、元素实现。元素声明用于给元素指定元素类型名称、内容和数据类型等属性。在 XSDL 中,元素声明可以是全局的,也可以是局部的。5.3.1 Schema 根元素在 XSD 中必须定义一个且只能定义一个 schema 根元素。根元素不但表明了文档类型,而且还包括模式的约束、XML 模式名称空间的定义,其他名称空间的定义、版本信息、语言信息和其他一些属性。定义如下:其中属性 name 指定 Schema 名称,也可以不需要。xmlns 指定所属名称空间,紧跟在后面的 xsd 则是该名称空间的名称,名称空间” http:/www.w3.org/2001/XMLSchema“被映射到 xsd 前缀,在后面
16、将详细说明名称空间。5.3.2 element 元素XSD 中的元素是利用 element 标识符来声明的。其中 name 属性是元素的名字,type 属性是元素值的类型,在这里可以是 XML Schema 中内置的数据类型或其他类型。具体定义如下:name 是元素类型的名称,必须是以字母或下划线开头,而且只能够包含字母、数字、下划线、连接符及句号。type 属性是必要的,说明元素的数据类型。下面的例子定义一个全局元素声明:author,为简单字符串类型。与以上文档对应的有效 XML 文档如下:罗贯中在元素的定义中还有 2 个属性:minOccurs 和 maxOccurs。其中minOccu
17、rs 定义了该元素在父元素中出现的最少次数(默认为 1,值为大于等于 0 的整数),maxOccurs 定义了该元素在父元素中出现的最多次数(默认为 1,值为大于等于 0 的整数)。在 maxOccurs 中可以把值设置为 unbounded,表示对元素出现的最多次数没有限制。表示元素 author 的类型为 string,出现的次数最少为 0(就是可选),最多不限制。一般来说,如果元素声明出现在 Schema 文档的顶级结构中,也就是说,它的父元素是 schema,那么这些元素为全局元素。相反,局部元素声明只出现在复杂类型定义内部,局部元素声明只在该类型定义中使用,而不被其他复杂类型引用或在
18、替换组中使用。不同的复杂类型,可以有相同元素类型名称的局部元素。【例 5.4】显示 title、author 和 price 三种局部元素声明的模式文档,code5_4.xsd5.3.3 设置默认值和固定值默认值和固定值通过给空元素增加值的方式来扩展实例。如果文档中存在空的元素,模式处理器根据模式文档的定义,会插入默认值或固定值。在 XSDL 中,默认值和固定值分别通过 default 和 fixed 属性设置。两个属性只能出现其中之一,它们是互斥的。如果元素为空,就填入默认值。下例中,声明了 city 元素,并指定了默认值为“佚名”。必须注意的是:元素声明中“空”的定义根据数据类型不同而有所
19、不同。某些数据类型允许空值,包括 string 等。任何允许空字符串值的类型,元素都不会认为是空的,从而对于字符串类型元素,默认值不会被填充。相反,integer 数据类型的空元素通常会被认为是空的,从而将填入默认值。此外,如果元素的 xsi:nil 属性被设置为 true,那么就不会插入它的默认值。元素的默认值行为见表 5.1。表 5.1 元素的默认值行为情 况 扩充实例结果 扩充之前 扩充之后指定值 保持原始值 罗贯中 罗贯中空元素(integer) 填充值 30空元素(string) 没有填充值 元素为空 没有填充值 固定值与默认值在相同的情况下添加,它们的差别仅在于如果元素拥有一个值,
20、则该值必须和固定值相等。当模式解析器确定元素值和固定值实际上是否相等时,会考虑到元素的数据类型。price 元素的数据类型为 integer,所以整数 1 的所有形式在实例中都会被接受,包括01、+1 和周围包含空白符的 1。相反,对于 author 元素具有数据类型string。字符串“01“是无效的,因为与字符串“1“并不相等。按照以上定义,元素的固定值行为见表 5.2。表 5.2 元素的固定值行为有效实例 无效实例1 201 01+1 +11 5.3.4 引用元素和替代引用是利用 element 标记符的 ref 属性实现的。主要适用于避免在文档中多次定义同一个元素,应当将经常使用的元素
21、定义为根元素的子元素,即为全局元素,这样方便在文档的任何地方引用它。如每本书籍都有作者,其它产品也会有作者,因此可以把 author 属性声明为全局元素,供文档中多处引用。【例 5.5】引用元素定义的模式文档,code5_5.xsd在这里还可以为某个定义的元素起一个别名,主要是利用 element标识符中的属性 substitutionGroup 实现的。方法如下: 以上文档对应的有效 XML 文档如下:罗贯中或者:string5.4 Schema 属性声明 上一节 下一节 本章开头属性声明用于命名属性并使之与某个特定的简单类型相关联。在XSDL 中,实现的方法是使用 attribute 元素
22、。在 XML Schema 文档中可以按照定义元素的方法定义属性,但受限制的程度较高。它们只能是简单类型,只能包含文本,且没有子属性。属性是没有顺序的,而元素是有顺序的。使用属性十分简练,元素的功能比属性强大,但在某些场合属性是非常有用的。通常,对于元数据使用属性,而对于数据则使用元素。如,用属性描述单位、语言或元素值的时间相依性。5.4.1 创建属性定义属性方法如下:该语句定义了一个名为 isbn 的属性,它的值必须是一个字符类型。属性也分全局和局部属性。全局声明的属性是 schema 元素的子元素,在模式文档中必须是唯一的。复杂类型的元素,使用 ref 属性通过名称来引用属性。局部属性声明
23、只出现在复杂类型定义中,它们仅能在类型定义中使用,而不能被其他类型重用。下面的例子显示了两个属性isbn 和 amount 的全局声明,然后定义了一个复杂类型,使用 ref 属性通过名称来引用这两个属性。use 属性用于指示属性是必需的还是可选的,它出现在属性引用而不是属性声明中,这是因为它关系到属性在复杂类型中的出现,而不是属性本身。上面的例子定义的是全局的属性定义方式,如果要在复杂类型里声明属性,可以参照下面的例子:rbut上面的例子描述了 isbn 和 amount 两个属性的局部声明,它们完全出现在复杂类型定义中。局部声明的属性名称作用范围仅限于复杂类型内,在同一个复杂类型定义中,两个
24、属性使用相同的限定名称是非法的。只有当属性会被多个名称空间的多个元素声明使用到时,才提倡将该属性声明为全局属性。5.4.2 为属性指派类型所有的属性声明都把属性指定为某种简单类型。所有的属性都具有简单类型而不是复杂类型,因为它们本身不能有子元素和属性。属性声明有三种方式:1. 在属性声明中通过用 type 属性指定命名简单类型。它可以是内置类型,也可以是用户自定义类型。2. 通过指定 simpleType 子属性来指定匿名类型。3. 既没有 type 属性,又没有 simpleType 子属性,从而不指定特定类型。在这种情况下,属性的类型为 anySimpleType,它可以拥有任何值,只有它
25、是结构合理的 XML 文档。下例显示四个属性的声明,采用了不同的类型指定方法。定义了grade 属性并赋予 gradeType 类型,amount 属性指定了内置类型integer,同时使用内嵌的匿名简单类型来声明 bookcategory 属性,第四个属性 anything 没有指定特定的类型。5.4.3 属性的默认值和固定值对于属性来说,也可以通过默认值和固定值的方式增加未出现的属性来扩充实例。定义和扩充的方式与元素一致。在 XSDL 中,默认值和固定值分别通过 default 和 fixed 属性设置。两个属性只能出现其中之一,它们是互斥的。如果属性在元素中缺失,它的默认值将会被填入。如
26、果属性出现,且包含任意值,它将保持该值不变。下面的例子显示了 book 元素的声明,它包含一个属性 amount,该属性被指定了默认值。固定值与默认值在基本一样的情况下被插入,区别在于,其值应和固定值相等。同时也会考虑属性的类型。5.5 Schema 的数据类型 上一节 下一节 本章开头W3C XML Schema 可以把 XML 文档中的元素声明为特定的类型,准许解析器检查文档的内容及其结构。XML Schema 定义了两种主要的数据类型:预定义简单类型和复杂类型。这两种数据类型之间的主要区别是复杂类型可以象数据一样包含其他元素而简单类型则只能包含数据。简单类型给予了 XML Schema
27、低级类型检查能力。5.5.1 简单类型元素和属性声明都可以使用简单类型来描述数据类型。1. 简单类型的种类原子类型(不可分割的类型,如 string, integer 等系统内建的类型)、列表类型、联合类型合起来统一称为简单类型。XML Schema 具有低级类型检查能力,允许把元素定义为表 5.3 中的任何类型之一。赋予简单类型的元素具有字符类型内容,但没有子元素或属性。原子类型具有不可分割的值,如 10 和 large 列表类型的值为用空白符隔开的原子值列表,如10 large 2 联合类型的值可以是原子值,也可以是列表值。它们的区别在于该类型的有效值集是两个或多个其他简单类型值空间的联合
28、。如要对于学生的成绩评定等级,可以定义一个联合类型,它允许的值既可以是 0 到 100 的整数,也可以是优、良、合格或不合格。表 5.3 XML Schema 支持的部分简单类型内建类型 定义string 字符串数据,如“online book shop“boolean 二元类型的 True 或者 False。date 表示日期,格式是 CCYY-MM-DD。dateTime表示当前时间,由日期和时间组成,如 11/18/80,10:00amtime 24 小时格式的时间可根据时区调节。decimal 任意精度和位数的十进制数,如 27.93integer 整数,如 34float 标准的 3
29、2 位浮点数,如 11.87e-2在前面一些例子中,有几个元素和属性被声明为简单类型。其中一些简单类型如 string 和 integer 是 XML Schema 中内置的,其它的一些则是源于(如果使用对象技术的语言就是继承)内置的类型。除此之外,新的简单类型可以通过从现有的简单类型(内置的简单类型以及源于内置简单类型的简单类型)引出定义。通常,通过重新约束一个现存的简单类型来引出一个新的简单类型。换句话说,新类型的合法值范围是现有类型的值范围的子集。使用 simpleType 元素来定义和命名新的简单类型,使用 restriction 元素来指出现有的基类型,并且用它来标识约束值范围的细节
30、。 假设希望建立一个新的整数类型称为 myInteger,它的值范围为10000 到 99999。那么定义应当基于简单类型 integer,然后定义它的值范围为 10000 到 99999。为了定义 myInteger,这样来约束 integer的范围,示例如下:这个例子显示了由一个基本类型定义和两个值域区间方面描述的组合,通过这三个要素对 myInteger 实施定义。2. 简单类型命名定义简单类型既可以为命名简单类型又可以为匿名简单类型。命名简单类型总是在全局定义,而且要求在模式的数据类型中具有唯一名称。类型的名称必须为 XML 无冒号名称,即必须是字母或下划线开始,只能包含字、数字、下划
31、线、连字符和句号。如上面的例子,简单类型名为 myInteger。这种类型的模式构造非常直截了当,但有些不实用。特别是如果定义了许多只应用一次而且包含非常少约束的类型,在这种情况下,一个类型应该能够被更简单的定义。这样的简单定义通常的形式是一个节省了名称和外部引用开销的匿名类型。在下面的示例中,publish 元素声明使用了匿名类型定义。一般的来说,通过元素中是否包含“type=”这个属性可以判断匿名元素定义(或者是匿名属性定义)。如果出现无名称的类型定义,也可以认为是匿名元素(属性)定义。 3. 简单类型的限制每个简单类型都是从另一个简单类型派生而来,这另一个简单类型称为基类型。派生可以从原
32、子类型,也可以从用户定义的简单类型派生。上面的例子都从内置的原子类型派生成新的简单类型。所有新的简单类型都以某种方式限制其基类型的值空间。下面的例子从上面定义的 myInteger 类型进一步限制:简单类型定义时,都是通过 restriction 元素来定义限制,通过base 属性来规定一种基类型。在 restriction 内,可以以任何顺序指定任何面(facet),来对类型取值进一步限制。根据面的不同,这个元素或属性具有不同的有效值。表 5.4 是 XML Schema 面的定义。对每个内置的原子类型,都有一套定义时可用的面。如果某个面适用于某种原子类型,那么也适用于派生于该类型的简单类型
33、。这里有必要举例说明枚举的简单类型定义,下面的例子定义了一个简单类型category,用于说明书籍的类别:表 5.4 XML Schema 面的定义面 意 义minExclusive 值必须大于 x,相对就有 maxExclusiveminInclusive 值必须大于等于 x,相对就有maxInclusivelength 值的长度必须等于 xminLength 值的长度必须大于等于 x,相对就有maxLengthtotalDigits 有效的数字的位数必须小于等于 xfractionDigits 小数位数必须小于等于 xwhiteSpace 应该保留、替换或压缩 whitespace,决定于
34、 xenumeration x 是一个有效值pattern x 是值可以匹配一个正则表达式4. 列表类型除了使用简单类型中描述的原子类型,XML Schema 还定义了其它两种简单类型:列表类型和联合类型。列表类型是由一组原子类型组成,因此它的每一个部分(原子)本身都是有意义的,定义时以空格隔开原子值的列表。举例来说category 是个列表类型。这个类型的元素将是 NMTOKEN 的列表,不同的 NMTOKEN 值间使用空格分隔,如“小说 散文 传记”。XML Schema有三个内置的列表类型,它们是 NMTOKENS、IDREFS 和 ENTITIES。除了使用内置的列表类型之外,还可以通
35、过引用现有的原子类型建立新的列表类型(不可以使用现有的列表类型来建立新的列表类型,也不能使用复合类型来建立新的列表类型)。举例来说,可以建立一个名为 myInteger 的列表类型,并在实例文档中使用它。其中示例中的后半部分即为实例文档中与列表类型 listOfMyIntType 相一致的实例元素 myInt。 20003 15037 95977 95945 一些用于描述的参数能够被应用到列表类型的定义中,它们是length、minLength、maxLength 和 enumeration。举例来说,如果想定义一个列表类型,这个列表类型正好包含了六个分类项名。首先从category 类型定义
36、一个新的列表类型,称为 cateList,然后通过限制cateList 导出只有三个项的 threeBookCate 类型。具体的定义可参见下例。 小说 散文 传记 类型为 threeBookCate 的元素必须有三个项,它们中的每一个项必须是一个枚举类型 category 的原子类型(枚举类型将在后面介绍),在示例的后半部分的实例文档中就是一个具体的应用例子。需要注意的是,从原子类型 string 可以导出一个列表类型,然而,在一个 string 中也许会带有空格,而空格在一个列表类型实例中是作为分隔符使用的。所以当在使用基类型为 string 的列表类型时,应当格外小心。举例来说,假设定义
37、了一个 length 取值为 3 的列表类型,同时这个列表类型是基于类型 string。下面由三个元素组成的列表是合法的:”Asia Europe Africa”;而由三个元素这样组成的列表是不合法的:”Asia Europe Latin America”。即使”Latin America”在列表外可以作为单独的一个字符串存在,但当它包含在列表中,在 Latin 和 America 之间的空格使得第四个项被有效地生成了,因此后面的例子不符合只有三个项的列表类型定义。5. 联合类型应用原子类型和列表类型,一个元素或者属性的值可以为一个或者多个原子类型(列表类型)的实例。与之相比较,一个应用联合类
38、型(Union Type)包含了多个原子类型或者列表类型,而应用了联合类型的元素或是属性的值可以是这些原子类型或列表类型中的一个类型实例。为了说明这一点,建立一个用于表示学生成绩的由评定等级或者数字列表的联合类型。gradeUnion 联合类型由一个原子类型和一个列表类型构成。组成联合类型的简单类型称为它的成员类型。成员类型必须是简单类型,不存在复杂类型的联合。除了直接用简单类型来规定成员类型外,还可以使用 union 元素的 memberTypes 属性来规定成员类型。假定已经在模式文档的其他地方定义了 gradeType 和 scoreInteger,改写上面的例子:87 优当在定义一个联
39、合类型时,元素 union 的 memberTypes 属性的值包含了联合类型中所有类型的列表。现在,假定声明了一个 gradeUnion类型的元素,称为 stuScore,stuScore 元素有效的实例可参见上面实例。此外,对于联合类型而言,还有两个描述性质的参数 pattern 和enumeration 也可以应需要使用。 5.5.2 复杂类型复杂类型的元素拥有子元素和属性,也可以有字符内容。复杂类型和简单类型之间最根本的区别就是:复杂类型的内容中可以包含其他元素或属性,但简单类型既不能包含子元素,也不能带有任何属性。复杂类型有四种不同的内容类型:简单类型、纯元素类型、混合类型及空类型。
40、下例中给出了具有复杂类型的元素:book 是带有属性的元素、bookinfo 是包含子元素的纯元素复杂类型、chapter 是混合类型的复杂类型元素以及内容为空的元素 price。它们分别属于下面要描述的 4 种不同的内容类型。no.1三国演义罗贯中宴桃园豪杰三结义 斩黄巾英雄首立功话说天下大势,分久必合,合久必分。复杂类型由 complexType 元素创建,同简单类型一样,复杂类型可以命名,也可以是匿名的。命名的复杂类型可以被多个元素声明使用。一般在全局范围内定义。相反,匿名复杂类型完全在元素声明中进行定义,而且只可以被该声明使用一次。有三种不同的方法:单个 complexContent
41、子元素,可以使用它从一个复杂类型派生出新的复杂类型。 单个 simpleContent 子元素,用于从简单类型派生复杂类型 组(group、all、choice 或 sequence)加属性,用于定义一种非派生于特定类型的复杂类型。 1. 内容类型所谓元素的内容是在标记之间的字符数据和子元素。复杂类型子元素的顺序和结构称为它的“内容模型”。复杂类型的内容类型有四种:简单类型、纯元素类型、混合类型和空类型。内容类型不依赖于属性,所有这些内容类型都允许有属性。简单内容只允许有字符数据,它没有子元素。一般说来,简单类型和具有简单内容的复杂类型的唯一区别在于后者可以有属性。如下面的 book 元素。n
42、o.1要定义如上所示的 book 元素,必须按如下方法定义。复杂类型bookType 的字符数据内容符合简单类型 string,而且还添加了 isbn属性。纯元素内容只允许有子元素,而没有字符数据内容。下例显示了具有纯元素内容的 bookinfo 元素,它有两个子元素:title 和 author。三国演义罗贯中可以按如下方式进行定义:混合内容既允许有字符数据又允许有子元素。经常用于字母和文档等形式自由的文本。下例中显示了具有混合内容的 chapter 元素。Chapter 元素中直接饱含字符数据,以及子元素 para。宴桃园豪杰三结义 斩黄巾英雄首立功话说天下大势,分久必合,合久必分。在创建
43、所示的 chapter 元素类型定义时,需要设置 complexType的 mixed 属性为 true,允许有字符数据内容。mixed 的默认值是false。空内容既不允许字符数据也不允许有子元素。带有空内容的元素通常在属性中具有值。有某些情况下,甚至可以没有属性,但空内容的元素存在本身就有意义。如 XHTML 中的元素就表示一个新行。要定义空内容元素的类型时,只需指定属性,不用作其它内容的说明。2. 利用组合器控制结构模式组允许把子元素声明或引用组合起来,从而构建更有意义的内容模型。模式组共有 3 种:all、choice、sequence。sequence 组合器,定义了一列元素并且必须
44、按照模式中指定的顺序显示,所有子元素,如果出现的话,都必须按照该顺序出现。示例如下:下面显示了一些 book 的有效实例。它的子元素都以正确的顺序出现:三国演义罗贯中文艺出版社choice 组合器用来声明只有一个相容元素必须出现,用于互斥情况。语法如下:下面的实例都是有效的,每一个实例包含一个符合 choice 组中声明的子元素。如果出现多个子元素,或者根本没有任何元素出现,那么该实例将是无效的。三国演义罗贯中choice 组还可以允许任意数量的子元素以任意顺序出现。这只要通过把 choice 组的 maxOccurs 属性设置为 unbounded 即可允许子元素以任何顺序出现,出现任意次数
45、。另外,为了指定更加高级的内容,sequence 和 choice 可以彼此嵌套,可以进行任意层数的嵌套。all 组合器来表示符合元素声明的所有元素都应该出现(以任何顺序)且只能出现一次。all 组合器与 choice 和 sequence 不同:只能包含元素声明和引用,而不能包含其它组。 不能出现多次。对于所包含的每个子元素,maxOccurs 必须为 1,而 minOccurs 只可以为 0 或 1。不能出现在其它模式组中。all 组必须在复杂类型的最高层。 语法如下:根据上面的定义,下面显示了 book 的两个有效实例。price 和publisher 元素定义了 minOccurs 等
46、于 0,所以可以不出现。三国演义罗贯中文艺出版社30三国演义罗贯中5.6 Schema 的名称空间 上一节 下一节 本章开头名称空间是 XML Schema 中的重要部分,它提供了一种避免元素命名冲突的方法。名称空间的用途在于为 XML 中使用的名称提供一个容器。5.6.1 命名冲突XML 是可扩展的,而这种扩展是不受到控制。因为 XML 文档中使用的元素不是固定的,那么多个不同的 XML 文档使用同一个名字来描述不同类型的元素的情况就可能发生。而这种情况又往往会导致命名冲突。请看下面两个例子如下 XML 文档在 table 元素中携带了水果的信息:ApplesBananas如下 XML 文档
47、在 table 元素中携带了桌子的信息:African Coffee Table80120如果上面两个 XML 文档片断碰巧在一起使用的话,那么将会出现命名冲突的情况。因为这两个片断都包含了元素,而这两个table 元素的定义与所包含的内容又各不相同。5.6.2 使用前缀解决命名冲突问题前面例子中所出现的命名冲突问题就是由于 XML 的可扩展性导致的,没有办法能够防止任何人以与其他人不兼容的方式对文档进行扩展。名称空间的出现就是为了解决这个问题。名称空间定义了一个标记的容器,为所有在文档使用的标记名称提供语境。实例文档中的元素类型或属性的名称可能直接与名称空间关联,或者就在属于某个名称空间。这
48、样就可以避免命名的冲突。因此,可以这样改造上面的 XML 文档,在 table 元素前面加上前缀:ApplesBananas则家具 table 的信息变成:African Coffee Table80120现在已经没有元素命名冲突的问题了,因为这两个文档对各自的table 元素使用了不同的前缀,table 元素在两个文档中分别是( 和)。但是,前缀还不能彻底解决问题,因为任何人都可以创建前缀,如果两个文档创建了相同的前缀,则又有冲突问题。为了避免前缀冲突,可以使用如下的前缀声明:f=“http:/www.example.org/html“h=“http:/www.example.org/fur
49、niture“将统一资源标识符(Uniform Resource Identifier,URI)跟前缀联系起来。因为 URI 跟标记或前缀不同,它具有唯一性的特点。这就是名称空间的解决方法。5.6.3 使用名称空间名称空间属性一般放置在元素的开始标记处,从属性 xmlns 开始,后面是前缀。其使用语法如下所示:xmlns:namespace-prefix=“namespace“具体示例如下:xmlns:f=“http:/www.w3.org/2000/10/XMLSchema前缀只是起着名称空间的代理的作用。名称空间的名称是 URI,而不是前缀,在比较两个元素时,解析器是根据 URI 来识别它们的名称空间,而不是根据前缀。上面的例子则可以与不同的名称空间关联到一起:ApplesBananas下面是携带了家具 table 的信息 XML 文档:African Coffee Table801205.6.4 URI、URL 和 URN名称空间的声明将一个全局名称(URI)跟元素的名称联系在一起。URI 只用作标识符。仅就作为 XML 名称空间来说,URI 不必是有效的。也就是说,它不必指向任何位置。XML 名称空间只将它们作为字符串处理。比较是逐个字符进行的,所以,下面的两个 URI 是不同的,虽然指向同一个文档。http:/www.ex