本文章系列是XML Schema的一个从入门到进阶的基本教程。内容主要翻译整理了W 3C 关于XML Schema的入门级规范:XML Schema Part 0: Primer( http://www.w3.org/TR/xmlschema-0/),同时译者添加了一些个人的编注,并重新整理安排了章节。
译者:柴晓路 ([email protected]), Chief System Architect
原文:http://www-128.ibm.com/developerworks/cn/xml/x-schema/part1/index.html
XML Schema是W 3C 的推荐标准,于2001年5月正式发布,经过数年的大规模讨论和开发,终于最终奠定下来,使得XML建模有了一个国际标准。XML Schema一确定下来,立刻成为全球公认得首选XML环境下的建模工具,已经基本取代了DTD在XML刚刚成为W 3C 推荐标准时的地位。由于XML是SGML的一个子集,因此它也继承了SGML世界中用于建模的DTD,当时使用DTD的好处是可以利用大量的在SGML世界中现有的DTD工具,使得开发应用代价维持在一个相对较低的水平。然而,DTD有着不少缺陷:1)DTD是基于正则表达式的,描述能力有限;2) DTD没有数据类型的支持,在大多数应用环境下能力不足;3) DTD的约束定义能力不足,无法对XML实例文档作出更细致的语义限制;4) DTD的结构不够结构化,重用的代价相对较高;5)DTD并非使用XML作为描述手段,而DTD的构建和访问并没有标准的编程接口,无法使用标准的编程方式进行DTD维护。而XML Schema正是针对这些DTD的缺点而设计的,XML Schema是完全使用XML作为描述手段,具有很强的描述能力、扩展能力和处理维护能力。
XML Schema的主要目的是用来定义一类XML文档(一个XML Application)。因此模式的"实例文档"形式常常用来描述一个与特定XML Schema相一致的XML文档。事实上,文档实例和Schema文档都不是必须要以文档的形式存在,他们可以存在以于应用之间传递的字节流的形式存在,或者作为一个数据库记录或者作为XML的"信息项"的集合而存在。然而为了简化入门,我们总是把实例和模式看作文档或者文件,认为它们总以文档实例或是模式文档的形式存在。让我们开始考虑一个在文件po.xml中的实例文档。它描述了一个由家庭产品采购和支付应用生成的购买订单。
po.xml,购买订单的XML实例文档 <?xml version="1.0"?> <purchaseOrder orderDate=" 1999-10-20 "> <shipTo country="US"> <name>Alice Smith</name> <street> 123 Maple Street </street> <city> Mill Valley </city> <state>CA</state> <zip>90952</zip> </shipTo> <billTo country="US"> <name>Robert Smith</name> <street> 8 Oak Avenue </street> <city> Old Town </city> <state>PA</state> <zip>95819</zip> </billTo> <comment>Hurry, my lawn is going wild!</comment> <items> <item partNum="872-AA"> <productName>Lawnmower</productName> <quantity>1</quantity> <USPrice>148.95</USPrice> <comment>Confirm this is electric</comment> </item> <item partNum="926-AA"> <productName>Baby Monitor</productName> <quantity>1</quantity> <USPrice>39.98</USPrice> <shipDate> 1999-05-21 </shipDate> </item> </items> </purchaseOrder> |
购买订单由一个主元素purchaseOrder和子元素shipTo、billTo、comment和items组成。这些子元素(除了comment)也依次包括其他子元素等等。直到一个像USPrice这样的子元素,它包含的是一个数字而不是任何子元素。元素如果包含子元素或者是带有属性则被称为复合类型;反之元素如果仅仅包含数字、字符串或者其他数据等,但不包含任何子元素则称为简单类型。
在实例文档中复合类型和一些简单类型是在购买定单的模式文档中定义。而其他一些标准的简单类型则是作为XML Schema内置的简单类型的指令表的一部分定义的。
在继续查阅购买订单模式文档之前,我们暂时离题来提一下实例文档和购买订单模式文档之间的联系。观察实例文档你可以看到购买订单模式文档并没有被提及。一个实例文档实际上不需要引用模式文档,当然尽管很多实例文档确实引用了,为了使这第一节简单化,我们一开始选择不引用。并且假设任何实例文档的处理器即使从实例文档中得不到任何信息,也能够包含购买订单模式文档的处理。在后面的章节,我们将介绍联系实例文档和模式文档的外部机制。
购买订单模式文档
购买订单模式文档包含在文件po.xsd中:
po.xsd,购买订单的Schema文档 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:annotation> <xsd:documentation xml:lang="en"> Purchase order schema for Example.com. Copyright 2000 Example.com. All rights reserved. </xsd:documentation> </xsd:annotation> <xsd:element name="purchaseOrder" type="PurchaseOrderType"/> <xsd:element name="comment" type="xsd:string"/> <xsd:complexType name="PurchaseOrderType"> <xsd:sequence> <xsd:element name="shipTo" type="USAddress"/> <xsd:element name="billTo" type="USAddress"/> <xsd:element ref="comment" minOccurs="0"/> <xsd:element name="items" type="Items"/> </xsd:sequence> <xsd:attribute name="orderDate" type="xsd:date"/> </xsd:complexType> <xsd:complexType name="USAddress"> <xsd:sequence> <xsd:element name="name" type="xsd:string"/> <xsd:element name="street" type="xsd:string"/> <xsd:element name="city" type="xsd:string"/> <xsd:element name="state" type="xsd:string"/> <xsd:element name="zip" type="xsd:decimal"/> </xsd:sequence> <xsd:attribute name="country" type="xsd:NMTOKEN" fixed="US"/> </xsd:complexType> <xsd:complexType name="Items"> <xsd:sequence> <xsd:element name="item" minOccurs="0" maxOccurs="unbounded"> <xsd:complexType> <xsd:sequence> <xsd:element name="productName" type="xsd:string"/> <xsd:element name="quantity"> <xsd:simpleType> <xsd:restriction base="xsd:positiveInteger"> <xsd:maxExclusive value="100"/> </xsd:restriction> </xsd:simpleType> </xsd:element> <xsd:element name="USPrice" type="xsd:decimal"/> <xsd:element ref="comment" minOccurs="0"/> <xsd:element name="shipDate" type="xsd:date" minOccurs="0"/> </xsd:sequence> <xsd:attribute name="partNum" type="SKU" use="required"/> </xsd:complexType> </xsd:element> </xsd:sequence> </xsd:complexType> <!-- Stock Keeping Unit, a code for identifying products --> <xsd:simpleType name="SKU"> <xsd:restriction base="xsd:string"> <xsd:pattern value="/d{3}-[A-Z]{2}"/> </xsd:restriction> </xsd:simpleType> </xsd:schema> |
购买订单模式文档由一个schema元素和一系列子元素组成,大多数子元素为element, complexType, 和simpleType,这些决定了在实例文档中的元素的表现方式和内容。
通过出现在schema元素中的命名空间声明xmlns:xsd="http://www.w3.org/2001/XMLSchema",在模式文档中的每一个元素都有一个与XML Schema命名空间相联系的命名空间前缀"xsd:"。尽管任何前缀都能够被使用,但是,前缀"xsd:"被约定用于表示XML Schema命名空间。通过使用同样的前缀,这样同样的关联也出现在内置的简单类型的名字中。例如,xsd:string。这种形式的关联的目的是用来标识元素和简单类型是属于XML Schema语言的词汇表而不是模式文档作者自己的词汇表。为了在这里清楚表示,我们仅提及元素的名字和简单类型(如simpleType)而忽略了它们的前缀"xsd:"。
复合类型定义,元素和属性声明
在XML Schema中,对于允许元素有他们自己的内容以及可以携带自身属性的复合类型与那些不能够有元素内容和属性的简单类型之间,有着基本的不同。而在实例文档中,对于能建立新的类型(无论简单和复杂)的定义和允许元素和属性有特定的名字和类型(无论是简单还是复杂)的声明之间,也有着显著的差别。在这一节中,我们将针对如何定义复合类型,以及如何声明使用复合类型的元素及其属性。
新的复合类型使用complexType元素来定义,这样的定义典型的包含一组元素声明,元素引用和属性声明。这些元素声明与其说是它们自身的类型,不如说是一由相关模式控制的名与控制这些名在实例文档中的表现形式的约束之间的关联。元素使用element元素声明,同时属性使用attribute来声明。举例来说,USAddress被定义为一个复合类型并且在USAddress定义中我们看到五个元素的声明和一个属性的声明。
<xsd:complexType name="USAddress" > <xsd:sequence> <xsd:element name="name" type="xsd:string"/> <xsd:element name="street" type="xsd:string"/> <xsd:element name="city" type="xsd:string"/> <xsd:element name="state" type="xsd:string"/> <xsd:element name="zip" type="xsd:decimal"/> </xsd:sequence> <xsd:attribute name="country" type="xsd:NMTOKEN" fixed="US"/> </xsd:complexType> |
这个定义的结果将是,在实例文档中出现的任何类型声明为USAddress的元素(比如在po.xml中的shiptTo)必须包含五个元素和一个属性。这些元素必须被命名为name、street、city、state和zip,这些名称就如同在模式声明中name属性的值所指的那样。并且这些属性必须按照模式声明中的同样的顺序出现。前四个元素必须包含一个字符串元素内容而第五个必须包含一个十进制数字类型的元素内容。声明为USAddress类型的元素可以带有一个country属性,该属性必须包含字符串"US"。
USAddress类型定义仅仅包含引用简单类型的声明:string、decimal 和NMTOKEN。与之对比,PurchaseOrderType类型定义则包含了引用复合类型的元素声明,如USAddress,虽然两个类型声明都使用同样的type属性来标识类型,而无需管类型是简单的还是复合的。
<xsd:complexType name="PurchaseOrderType"> <xsd:sequence> <xsd:element name="shipTo" type="USAddress"/> <xsd:element name="billTo" type="USAddress"/> <xsd:element ref="comment" minOccurs="0"/> <xsd:element name="items" type="Items"/> </xsd:sequence> <xsd:attribute name="orderDate" type="xsd:date"/> </xsd:complexType> |
在PurchaseOrderType的类型定义中,对于shipTo 和 billTo这两个子元素的声明,它们将不同的元素名字和相同的复合类型相关联,这个复合类型是USAddress。这个定义的结果是,如果在实例文档中出现的任何元素(如po.xml中),当元素类型被声明为PurchaseOrderType时,那么这个元素必须包含两个名为shipTo 和billTo的元素,这两个元素都要包含五个子元素(name、street、city、state和zip),这五个子元素是作为USAddress声明的一部分而出现的。应USAddress的相关类型定义,shipTo和billTo元素也可以包含country属性。
PurchaseOrderType类型定义包含了一个orderDate属性声明,就像在UAAddress中的country属性声明一样,它被标识为一个简单类型,实际上,所有的属性声明必须引用简单类型。这是因为不像元素声明,属性不能包含其他元素或者其他属性。迄今为止我们描述的元素声明对于每一个名字都和一个现存的类型定义相关联。然而有时候,使用一个现存的元素比定义一个新的元素更方便。
<xsd:element ref="comment" minOccurs="0"/> |
这个声明定义引用了一个现存的元素comment,该元素在购买订单模式文档中的其他地方有定义。一般的来说,ref属性的值必须指向一个全局元素,一般来说,应当是在下面声明的而不是作为复合类型定义的一部分声明的。这个声明的结果为一个叫comment的元素可以出现在实例文档的关于这个定义的相关部分中,他的内容必须和那个被引用的元素的类型一致,在这个情况下是" string"。
出现约束
我们看到,在前面中的元素声明中minOccurs属性的值为0 ,所以comment元素在PurchaseOrderType类型中是一个可选项。一般的来说,当minOccurs的值为1或者更多时,一个元素就必须出现。一个元素可以出现的最大数量由声明中的maxOccurs属性所决定的。这个值也许是一个正的整型如41,或者以"unbounded"的形式来表明不限最大的出现数量。minOccurs和maxOccurs属性的默认值是1。因此,当一个元素如comment,没有定义maxOccurs属性,元素不可以出现超过一次。如果你仅仅指定了minOccurs属性的值,它必须小于等于maxOccurs的默认值,也就是说minOccurs如果单独出现,其取值只能为0或者1。同样的,如果你只指定了maxOccurs属性,它必须大于等于minOccurs的默认值,也就是必须取值为1或者更多。如果两个属性都被省略了,那么元素必须出现且仅出现一次。
而对于属性而言,它可以出现一次或者更本不出现,不会有其他的出现次数,所以指定属性出现次数的语法与元素的语法有所不同。特别的,属性声明能够使用一个use属性来指明属性是否需要出现(参阅po.xsd中partNum属性的声明)。
属性和元素的默认值都是使用default属性来声明,不过这个属性在不同的情况下有些许不同的语义表示结果。当一个属性使用默认值来声明的时候,如果属性在实例文档中出现了,那么属性的值就是属性在实例文档中出现的那个值。如果属性没有在实例文档中出现,模式 处理器将认为这个属性的值等于声明中default属性的值。需要注意的是,属性默认值只在属性本身为"可选的"时候才有意义,如果在声明中,即指定了默认值,同时又设置了use属性为除"optional"以外的其他值的话,处理器就会产生错误。
而当一个元素声明中有默认值定义的时候,模式处理器在处理默认的元素值的时候,与处理属性的默认值相比有一些不同。如果实例文档中元素出现且带有自身的内容的时候,元素的值就是是实例文档中元素的内容,如果元素没有内容,那么模式处理器就认为这个元素的值(内容)等于声明中default属性的值。然而,如果元素在实例文档中并不出现,模式处理器则更本不认为该元素出现。总而言之,元素和属性默认值之间的区别可以认为是:当属性不出现时默认的属性值被应用,当元素内容为空的时候,默认的元素值被应用。
属性和元素声明中都使用到fixed属性来确保属性和元素被设置为特殊的值,如po.xsd中包含了一个country属性的声明,这个country属性声明就有一个fixed属性,值为US。这个声明意味着在实例文档中country属性的出现是可选的(use属性的默认值是optional),但是如果属性出现,他的值必须为"US",如果属性不出现,模式处理器将自动设置country属性值为"US"。需要注意的是,fixed值的概念和default值的概念是互斥的。所以如果同时声明fixed和default属性就会令模式处理器产生一个错误。
在元素和属性声明中用于约束他们出现行为的属性的值被概括地罗列在下表中:
元素 - 使用(minOccurs, maxOccurs) fixed, default |
属性 - 使用use, fixed, default |
注解 |
(1, 1) -, - |
required, -, - |
元素/属性必须出现一次,它可以有任何值。 |
(1, 1) 37, - |
Required, 37, - |
元素属性必须出现一次,他的值为37。 |
(2, unbounded) 37, - |
无相关描述 |
元素必须出现两次或者多次,他的值必须为37,一般说来,minOccurs 和maxOccurs可以为正数,maxOccurs可以为"unbounded"。 |
(0, 1) -, - |
optional, -, - |
元素/属性可以出现一次,他可以有任何值。 |
(0, 1) 37, - |
optional, 37, - |
元素/属性可以出现一次,如果出现他的值必须为37,如果不出现他的值为37。 |
(0, 1) -, 37 |
optional, -, 37 |
元素/属性可以出现一次,如果不出现值为37,否则他的值为给出的值。 |
(0, 2) -, 37 |
无相关描述 |
元素可以出现一次、两次或者更本不出现,如果元素不出现,则默认值不发生作用,如果出现并且他为空元素,则其值为37,否则值为实例中给出的值。一般说来,minOccurs 和maxOccurs可以为正数,maxOccurs可以为"unbounded"。 |
(0, 0) -, - |
prohibited, -, - |
元素/属性必须不出现。 |
在这里,值得注意的是,在全局的元素和属性声明中,minOccurs、maxOccurs、use都没有出现。
全局元素和属性
全局的元素和全局的属性是在全局声明时被建立的,全局声明都是作为元素的子元素出现的。一旦经过定义,全局元素或者全局属性可以像先前我们描述的那样使用ref属性在一个或多个声明中引用。一个引用全局元素的声明,允许被引用的元素在实例文档中出现在引用这个元素的声明相关的元素中。所以,举例来说, po.xml中的comment元素同样可以在shipTo、billTo和items元素中出现,因为引用comment的复合类型定义的声明同样出现在这三个元素的声明中。
一个全局元素的声明也允许元素在实例文档中以顶级的文档元素出现,因此purchaseOrder元素,在po.xsd中是作为一个全局元素声明的,能够作为po.xml.中的顶级元素出现。值得注意的是,基于这个基本原理, comment元素作为顶级元素出现在文档如po.xml中也是被允许的。
关于使用全局的元素和属性有很多忠告,其中一个忠告是全局的声明不能够包含引用。全局的声明定义不能包含ref 属性,他们必须使用type 属性(或者,像我们简短描述的,跟随一个匿名的类型的定义)。第二个忠告是约束不能够放在全局声明中。尽管他们能够放在引用全局声明的局部声明中。换句话说,全局声明不能够包含minOccurs、maxOccurs、或者use属性。
简单类型
在购买订单模式文档中,几个元素和属性被声明为简单类型,其中一些简单类型如 string 和decimal是XML Schema中内置的。而其他的一些则是源于(如果使用对象技术的语言,就是继承)内置的类型。举例来说,partNum属性的类型称为SKU(Stock Keeping Unit),是源于string.的。内置的简单类型和他们的后继版本都能够被用在所有的元素和属性声明中,下面的列表列举了所有的在XML Schema中内置的简单类型及其相应的例子。
简单类型 |
值示例 |
备注 |
string |
Confirm this is electric |
|
normalizedString |
Confirm this is electric |
参见 (3) |
token |
Confirm this is electric |
参见 (4) |
byte |
-1, 126 |
参见 (2) |
unsignedByte |
0, 126 |
参见 (2) |
base64Binary |
GpM7 |
|
hexBinary |
0FB7 |
|
integer |
-126789, -1, 0, 1, 126789 |
参见 (2) |
positiveInteger |
1, 126789 |
参见 (2) |
negativeInteger |
-126789, -1 |
参见 (2) |
nonNegativeInteger |
0, 1, 126789 |
参见 (2) |
nonPositiveInteger |
-126789, -1, 0 |
参见 (2) |
int |
-1, 126789675 |
参见 (2) |
unsignedInt |
0, 1267896754 |
参见 (2) |
long |
-1, 12678967543233 |
参见 (2) |
unsignedLong |
0, 12678967543233 |
参见 (2) |
short |
-1, 12678 |
参见 (2) |
unsignedShort |
0, 12678 |
参见 (2) |
decimal |
-1.23, 0, 123.4, 1000.00 |
参见 (2) |
float |
-INF, -1E4, -0, 0, 12.78E-2, 12, INF, NaN |
等同于单精度32位浮点数,其中”NaN”表示”不是一个数字”。参见 (2) |
double |
-INF, -1E4, -0, 0, 12.78E-2, 12, INF, NaN |
等同于双精度64位浮点数。参见 (2) |
boolean |
true, false1, 0 |
|
time |
13:20:00.000, 13:20:00.000-05:00 |
参见 (2) |
dateTime |
1999-05-31 T13:20:00.000-05:00 |
这个时间表示的含义是: 1999 年 5 月 31 日 美东标准时间下午1:20,注意后面的-05:00表示这个时间比格林尼治时间早5个小时。参见 (2) |
duration |
P1Y 2M3 DT10H 30M 12.3S |
这表示经过了1年2个月3天又10个小时30分钟12.3秒。 |
date |
1999-05-31 |
参见 (2) |
gMonth |
--05-- |
表示5月。参见 (2) (5) |
gYear |
1999 |
表示1999年。参见 (2) (5) |
gYearMonth |
1999-02 |
表示1999年2月,而并不关心是几号。参见 (2) (5) |
gDay |
---31 |
表示31号。参见 (2) (5) |
gMonthDay |
--05-31 |
表示每个5月31号。参见 (2) (5) |
Name |
shipTo |
XML 1.0的Name类型 |
QName |
po:USAddress |
XML命名空间的QName类型 |
NCName |
USAddress |
XML命名空间的NCName类型,即一个不带命名空间前缀修饰的QName |
anyURI |
http://www.example.com/, http://www.example.com/doc.html#ID5 |
|
language |
en-GB, en-US, fr |
XML 1.0中定义的合法语言代码 |
ID |
|
XML 1.0中定义的ID属性类型。参见 (1) |
IDREF |
|
XML 1.0中定义的IDREF属性类型。参见 (1) |
IDREFS |
|
XML 1.0中定义的IDREFS属性类型。参见 (1) |
ENTITY |
|
XML 1.0中定义的ENTITY属性类型。参见 (1) |
ENTITIES |
|
XML 1.0中定义的ENTITYS属性类型。参见 (1) |
NOTATION |
|
XML 1.0中定义的NOTATION属性类型。参见 (1) |
NMTOKEN |
US, Brésil |
XML 1.0中定义的NMTOKEN属性类型。参见 (1) |
NMTOKENS |
US UK , Brésil Canada Mexique |
XML 1.0中定义的NMTOKENS属性类型,即一个使用空格作为元素分隔的NMTOKEN列表。参见 (1) |
注意: 为了在XML Schema和XML 1.0 DTD之间保持兼容,简单类型ID、IDREF、IDREFS、ENTITY、ENTITIES、NOTATION、NMTOKEN、NMTOKENS只能用在属性定义中; 这个类型的值能够表示为不止一种格式,如100和1.0E2都是有效的float格式,它们都表示”一百”这个数值。然而,对于这个类型而言,已经为其定义了规范的格式规则。 换行符、制表符和回车符在normalizedString中将会在处理前被转化成空格字符 作为normalizedString,相邻的空格字符将会被合并为一个空格字符,第一个和最后的空格将被移走 “g”前缀表示罗马历的时间和年代。 |
新的简单类型通过从现有的简单类型(内置的简单类型以及源于内置简单类型的简单类型)引出定义。特别的,我们通过重新约束一个现存的简单类型来引出一个新的简单类型。换句话说,新类型的合法值范围是现有类型的值范围的子集。我们使用simpleType元素来定义和命名新的简单类型,我们使用restriction元素来指出现有的基类型。并且用它来标识约束值范围的细节。
假设我们希望建立一个新的整数类型称为myInteger,他的值范围为10000到99999。我们的定义应当基于简单类型integer,然后定义他的值范围为10000到99999。为了定义myInteger,我们这样来约束integer的范围(参见下图):
使用基类型来定义新的简单类型 <xsd:simpleType name="myInteger"> <xsd:restriction base="xsd:integer"> <xsd:minInclusive value="10000"/> <xsd:maxInclusive value="99999"/> </xsd:restriction> </xsd:simpleType> |
上面的例子显示了一个由一个基本类型定义和两个值域区间方面描述的组合,通过这三个要素来对myInteger实施了定义。
而先前的购买订单模式文档则包含了其他的更详细的定义简单类型的例子。一个叫SKU的新简单类型(参见下图)是从(通过约束)简单类型string引出的。此外,我们使用一个称为pattern的描述以及pattern的正则表达式值"/d{3}-[A-Z]{2}"来约束SKU的值。其中,该正则表达式值的语义为:3个数字后面跟着一个连字号接着跟着两个大写的英文字母"。
<xsd:simpleType name="SKU"> <xsd:restriction base="xsd:string"> <xsd:pattern value="/d{3}-[A-Z]{2}"/> </xsd:restriction> </xsd:simpleType> |
XML Schema定义了15用于简单类型定义描述的词汇。在这些词汇中,enumeration是特别有用的,他能够被用于约束除boolean类型之外的几乎每一个简单类型。enumeration限制简单类型的值为一系列不同的枚举值。举例来说,我们可以使用enumeration来定义一个新类型称为USState(参见下图),USState是从string引出的,同时它的值必须为美国州的缩写。
<xsd:simpleType name="USState"> <xsd:restriction base="xsd:string"> <xsd:enumeration value="AK"/> <xsd:enumeration value=" AL "/> <xsd:enumeration value="AR"/> <!-- and so on ... --> </xsd:restriction> </xsd:simpleType> |
USState将会在现在使用的state元素声明中成为string类型的一个非常好的替换品。通过使用这个替换品可以使state元素具有合法值的校验能力。举例来说,billTo和shipTo元素的子元素state,将会被限制在AK,AL,AR等等中。注意到对于特定类型的列举值必须是唯一的。
列表类型(List Type)
除了在前面描述简单类型的那个表格中列出的原子类型(这些原子类型可用于组合成绝大多数的其他类型,包括其他的简单类型和复合类型)外,XML Schema中在简单类型范畴中还有列表类型的概念。(原子类型、列表类型以及将在下一节中描述的组合类型,总称为简单类型)。一个原子类型的值在XML Schema中是不可分割的。举例来说,NMTOKEN值US是不可分割的,US的任何部分,如字母S本身都是没有意义的。与之相比较,列表类型则是由一组原子类型组成,因此它的每一个部分(原子)本身都是有意义的。举例来说NMTOKENS是个列表类型。这个类型的元素将是NMTOKEN的列表,不同的NMTOKEN值间使用空格分隔,如"US UK FR"。XML Schema有三个内置的列表类型,他们是NMTOKENS、IDREFS和ENTITIES。
除了使用内置的列表类型之外,你还可以通过引用现有的原子类型来建立新的列表类型(你不可以使用现有的列表类型来建立新的列表类型。也不能使用复合类型来建立新的列表类型)。举例来说,我们可以建立一个名为myInteger的列表类型,并在实例文档中使用它(参见下图)。其中下图中的后半部分即为实例文档中与列表类型listOfMyIntType相一致的实例元素。
<!-- Schema Fragment --> <xsd:simpleType name="listOfMyIntType"> <xsd:list itemType="myInteger"/> </xsd:simpleType> <!-- Instance Fragment --> <listOfMyInt>20003 15037 95977 95945</listOfMyInt> |
一些用于描述的参数能够被应用到列表类型的定义中,它们是:length、minLength、maxLength和enumeration。举例来说,如果我们想定义一个列表,这个列表正好包含了六个美国的州名(SixUSStates)。我们首先从USState定义了一个新的列表类型,称为USStateList,然后我们通过限制USStateList 只有六个项来导出SixUSStates。具体的定义可参见下图。
<!-- Schema Fragment --> <xsd:simpleType name="USStateList"> <xsd:list itemType="USState"/> </xsd:simpleType> <xsd:simpleType name="SixUSStates"> <xsd:restriction base="USStateList"> <xsd:length value="6"/> </xsd:restriction> </xsd:simpleType> <!-- Instance Fragment --> <sixStates>PA NY CA NY LA AK </sixStates> |
类型为SixUSStates的元素必须有六个项,他们中的每一个必须是一个枚举类型USState的原子类型,在上图后半部分的实例文档中就是一个具体的应用例子。
此时,我们需要注意的是,我们可以从原子类型string导出一个列表类型,然而,在一个string中也许会带有空格,而空格在一个列表类型实例中是作为分隔符使用的。所以当在使用基类型为string的列表类型时,应当格外小心。举例来说,假设我们定义了一个length取值为3的列表类型,同时这个列表类型是基于类型string。以下的由三个元素组成的列表是合法的:"Asie Europe Afrique",而下面的由三个元素组成的列表则是不合法的:"Asie Europe Amérique Latine"。
即使"Amérique Latine"在列表外可以作为单独的一个字符串存在,但当它包含在列表中,在Amérique和Latine之间的空格使得第四个项被有效地生成了,因此后面的那个例子不符合只有三个项的列表类型定义。
联合类型(Union Type)
应用原子类型和列表类型,一个元素或者属性的值可以为一个或者多个原子类型(列表类型)的实例。与之相比较,如果应用联合类型,一个联合类型包含了多个原子类型或者列表类型,而应用了联合类型的元素或是属性的值可以是这些原子类型或列表类型中的一个类型的实例。为了显示这点,我们建立一个用于表示美国的州的,为两个字母缩写或者数字列表的联合类型。zipUnion联合类型由一个原子类型和一个列表类型构成的(参见下图)。
<!-- Schema Fragment --> <xsd:simpleType name="zipUnion"> <xsd:union memberTypes="USState listOfMyIntType"/> </xsd:simpleType> <!-- Instance Fragment --> <zips>CA</zips> <zips>95630 95977 95945</zips> <zips>AK</zips> |
当我们在定义一个联合类型时,元素union的memberTypes属性的值包含了联合类型中所有类型的列表。现在,假定我们声明了一个zipUnion类型的元素,称为zips,zips元素有效的实例可参见上图。
此外,对于联合类型而言,还有两个描述性质的参数pattern和enumeration也可以应需要使用。