4.2 XML Schema 入门
虽然XML Schema 完全基于XML,且号称更简单易用,但对很多初学者而言,XML Schema比DTD更复杂,主要是因为Schema本身有语义约束,而且在XML文档中导入Schema也更烦琐一些。
4.2.1 XML Schema根元素
XML Schema本身是一个XML文档,因此它完全遵守XML的基本规则,其根元素是<schema…/>元素。最简单的XML Schema 有如下形式:
上述XML Schema的根元素中指定了xmlns:xs="http://www.w3.org/2001/XMLSchema",这是因为XML Schema本身也是XML文档,也需要语义约束。关于上述粗体字代码的解释如下:
xmlns[:xxx]属性用于为指定XML文档引入语义约束。该属性的属性值就是该文本所使用的语义约束对应的命名空间。xxx是一个任意的标识名,该标识名将作为该语义约束所定义的所有元素的前缀(前缀和标签名之间以英文冒号隔开),用于代表该语义约束所对应的命名空间。
提示
不同语义约束(Schema或DTD)下可能包含同名的元素,为了在同一份XML文档中使用不同语义约束下的同名元素,需要在这些元素前增加特定的前缀,不同的前缀实质上代表了不同的语义约束。
"http://www.w3.org/2001/XMLSchema"属性值指定了XML Schema语义约束的命名空间。前面已经提到,XML Schema也是XML文档,也需要语义约束,这些语义约束文档可登录http://www.w3.org/2001/XMLSchema站点查看。
采用上述格式定义的XML Schema将没有对应的命名空间,如果希望为其指定对应的命名空间,则应按如下格式来定义其根元素:
关于上述Schema中粗体字代码的解释如下:
targetNamespace="http://www.crazyit.org/Schema":指定该Schema的目标命名空间为http://www.crazyit.org/Schema。也就是说,当需要引用该XML Schema里定义的Schema组件(包括元素、属性和类型等)时,通常需要使用该命名空间对应的前缀作为限定。
不管是XML文档本身,还是XML Schema文档,它们的根元素都可以接受任意多个xmlns[:xxx]属性,其中[:xxx]部分是可选的,xxx可以是任意合法的标识名。这个属性也是许多XML Schema初学者最迷惑的地方。其实所有xmlns[:xxx]的作用都完全一样,下面是各种xmlns[:xxx]属性的通用形式:
xmlns[:xxx]="schemaNamespace":指定使用schemaNamespace命名空间下的Schema组件时,应该使用xxx前缀作为限定。如果指定该属性时省略了[:xxx]部分,那就是说使用schemaNamespace命名空间下的Schema组件时,无须使用任何前缀作为限定。
提示
让targetNamespace属性值和xmlns属性值完全相等是较为简单的情形:此时使用该Schema里定义的任何Schema组件都不需要前缀限定。否则,需要为<schema…/>根元素再增加一个形如xmlns:xxx="targetNamespace属性值"的属性,用于导入当前XML Schema里定义的Schema组件。
除此之外,还可以为schema元素指定如下两个属性:
elementFormDefault:该属性值可以是qualified或unqualified,用于指定XML文档使用该Schema 中定义的局部元素时是否必须用命名空间限定。
attributeFormDefault:该属性值可以是qualified或unqualified,用于指定XML文档使用该Schema 中定义的局部属性时是否必须用命名空间限定。
提示
关于elementFormDefault和attributeFormDefault两个属性,在第6章关于命名空间的知识里有更多深入的介绍。
掌握了XML Schema的根元素之后,至于如何利用XML Schema为XML文档定义语义约束则是后面章节需要介绍的内容了。
4.2.2 在XML中引用无命名空间的Schema
编写了XML Schema语义约束之后,必须将其导入目标XML文档中,来对目标XML文档进行有效性限制。从前面对XML Schema根元素的介绍可以知道,XML Schema定义的语义约束有两种:有命名空间的和无命名空间的。
向XML文档中导入无命名空间的Schema比较简单,只需在其文档根元素里增加如下两个属性即可:
xmlns:xsi:该属性值总是"http://www.w3.org/2001/XMLSchema-instance"。该属性及其值对所有XML文档通常都是固定的。
提示
上面的属性其实是导入了http://www.w3.org/2001/XMLSchema-instance命名空间对应的XML Schema,表明使用该XML Schema定义的Schema组件时需要使用xsi前缀作为限定。
xsi:noNamespaceSchemaLocation:该属性值用于指定XML Schema文件的URI,既可是绝对的URL地址,也可是位于磁盘上的相对路径。
提示
实际上noNamespaceSchemaLocation属性就是http://www.w3.org/2001/XMLSchemainstance命名空间对应的XML Schema所定义的属性,因此使用该属性时需要增加xsi前缀作为限定。由此可见,该xsi前缀是可变的,只要保证xmlns:xxx的后缀和xxx:noNamespace SchemaLocation的前缀相同即可。
例如如下XML文档:
程序清单:codes\04\4.2\bookNoNamespace.xml
上面的XML文档中导入了noNamespaceBook.xsd文件作为语义约束,该属性值不是绝对的URL地址,而是简单的相对地址,因此该文件应该放在与bookNoNamespace.xml文件相同的位置。
4.2.3 在XML中引用有命名空间的Schema
向XML文档中引入有命名空间的XML Schema其实也很简单,按如下两步操作即可:
(1)每引入一个有命名空间的XML Schema就为XML根元素增加一个xmlns[:xxx]属性,其中[:xxx]是可选的,但最多只能有一个xmlns属性,其他的都必须是形如xmlns:xxx的属性,而且xxx应该互不相同。表明使用各命名空间对应的XML Schema所定义的Schema组件时应该使用xxx前缀作为限定。
(2)如果XML根元素中已有xsi:schemaLocation属性(xsi前缀可变),则在该属性值后为该XML Schema追加一项,追加项要保持schemaNamespace schemaURI的格式。如果XML根元素中还没有xsi:schemaLocation属性,则为其增加该属性,并设置属性值为schemaNamespace schemaURI。
如下XML文档中不仅包含了无命名空间的Schema,也包含了有命名空间的Schema:
程序清单:codes\04\4.2\book.xml
上述XML文档中的①号代码用于引入无命名空间的XML Schema,引入无命名空间的XML Schema只需通过xsi:noNamespaceSchemaLocation属性指定Schema的URI即可。
②号代码指定了使用http://www.crazyit.org/crazy命名空间的XML Schema所定义的Schema组件时,必须使用crazy前缀作为限定。
③号代码指定了有命名空间的XML Schema的命名空间及其URI。
如果需要为XML文档再引入一个有命名空间的XML Schema,同样按上面介绍的两步操作即可,例如下面的XML文档就导入了2个有命名空间的XML Schema:
程序清单:codes\04\4.2\book2Namespace.xml
由此可见,一份XML文档中可以引入无数份有命名空间的XML Schema,但最多只能引入一份无命名空间的XML Schema。很明显,有命名空间的XML Schema具有更好的可扩展性,因此通常建议定义XML Schema时为其根元素指定targetNamespace属性,该属性的属性值就是该XML Schema所对应的命名空间。