4.11 合并多个Schema

Schema比DTD更优秀的一个地方体现在它支持模块化开发,开发人员可以将不同模块的XML组件定义在不同的Schema中,再将多个Schema合并为一个整体。Schema提供了3种方式来合并Schema,下面依次介绍这些方式。

4.11.1 使用include元素

<include…/>元素可以将另一份Schema包含到当前Schema中,使用<include…/>元素包含另一份Schema有如下几个要求:

alt <include…/>元素必须作为Schema的根元素<schema…/>的子元素。

alt <include…/>元素必须放在<schema…/>元素的开头,只有<import…/>、<redefine…/>和<annotation…/>元素可放在<include…/>元素之前。

alt 使用<include…/>元素包含的Schema要么没有目标命名空间,要么其目标命名空间与当前Schema的目标命名空间相同。这意味着,使用<include…/>元素包含进来的Schema将不再保留它本身的命名空间,被包含Schema所定义的全部组件都将放入当前Schema的命名空间下。


alt提示

前面介绍<include…/>元素必须放在<schema…/>元素的开始部分,这一点很容易理解:因为它的作用有点类似于Java中的import语句和C语言中的#include语句,而且Schema支持3种导入元素:<include…/>、<import…/>和<redefine…/>,因此它们都必须放在<schema…/>元素的开始部分,而这3种元素之间则没有顺序要求。


<include…/>元素的使用非常简单,只需指定如下两个属性即可:

alt id:指定该<include…/>元素的唯一标识,通常无须指定。

alt schemaLocation:指定<include…/>元素包含的Schema的位置,该属性值既可以是相对位置,也可以是绝对位置。这是个必填属性。

如下Schema中定义了一个age_Type类型:

程序清单:codes\04\4.11\included.xsd

alt

上面的Schema文档中定义了一个age_Type类型,为了在另一份Schema文档中复用这个类型,将其包含到那份Schema文档中即可,如以下Schema文档所示:

程序清单:codes\04\4.11\include.xsd

alt

上面的Schema文档中的粗体字代码包含了另一份Schema文档,被包含Schema没有自己的目标命名空间,因此其所定义的age_Type类型将被完全引入到当前命名空间内,从而在当前Schema中定义<age…/>元素时,可以直接指定type="age_Type"——就像当前Schema中定义了age_Type类型一样。

4.11.2 使用redefine元素

基本上,可以把<redefine…/>元素当成<include…/>元素的增强版,它完全可以取代<include…/>元素,因此可以将上面include.xsd中的<include…/>元素替换成<redefine…/>元素。

实际上,使用<redefine…/>元素包含Schema的前提条件和需要指定的属性都与使用<include…/>元素时完全相同。<redefine…/>元素增强了<include…/>元素的功能,它允许当前Schema重定义被包含Schema里的Schema组件,包括重定义类型、重定义元素组和重定义属性组等。


alt提示

关于元素组、属性组的知识请参考第5章的内容。


为了重定义被包含Schema里的组件,<redefine…/>元素里可以接受<simpleType…/>(用于重定义简单类型)、<complexType…/>(用于重定义复杂类型)等子元素。

值得注意的是,对于<redefine…/>元素里重定义的组件有如下3个要求:

alt 重定义的组件必须是被<redefine…/>包含进来的Schema里已有的组件。

alt 重定义的组件只能基于被包含Schema里已有的组件增加限制(利用<restriction…/>)或增加扩展(利用<extension…/>)。

alt 如果是采用增加限制的方式来重定义原有的组件,则<restriction…/>元素里所包含的约束不能违反原类型里已有的约束。

如下Schema里定义了一个age_Type类型:

程序清单:codes\04\4.11\redefined.xsd

alt

上面的Schema没有自己的目标命名空间,只是定义了一个简单的age_Type类型,下面的Schema将使用<redefine…./>元素来包含它,并重定义age_Type类型:

程序清单:codes\04\4.11\redefine.xsd

alt

上面的Schema中的粗体字代码使用<redefine…/>元素包含了redefined.xsd,并重定义了其中的age_Type类型。其中①号代码指定重定义age_Type,这个类型是原Schema中已有的类型,符合规则;②号代码指定对原有的age_Type增加额外的限制,符合规则;③号代码指定增加额外的maxExclusive约束,该约束值为80,没有违反原来的maxExclusive约束(原来的约束值为100),符合规则。由此可见,上面的Schema文档成功地重定义了age_Type类型。

4.11.3 使用import元素

<import…/>元素可以将另一份Schema包含到当前Schema中,使用<import…/>元素导入另一份Schema有如下几个要求:

alt <import…/>元素必须作为Schema的根元素<schema…/>的子元素。

alt <import…/>元素必须放在<schema…/>元素的开头,只有<include…/>、<redefine…/>和<annotation…/> 元素可放在<import…/>元素之前。

alt 使用<import…/>元素导入的Schema要么没有目标命名空间,要么其目标命名空间与当前Schema的目标命名空间不同,而且被导入Schema和导入Schema不能同时没有目标命名空间。简单地说,被导入Schema和当前Schema的目标命名空间绝对不能相同!这意味着,使用<import…/>元素导入的Schema一定要保留它原来的命名空间,使用被导入Schema里的Schema组件时应该添加前缀作为限定(除非被导入Schema没有命名空间)。

<import…/>元素的使用非常简单,只需指定如下3个属性即可:

alt id:指定该<import…/>元素的唯一标识,通常无须指定。

alt schemaLocation:指定该<import…/>元素包含的Schema的位置,该属性值既可以是相对位置,也可以是绝对位置。这是个必填属性。

alt namespace:指定被导入Schema的目标命名空间。被导入Schema没有目标命名空间时,该属性可以省略。

如下Schema中定义了一个age_Type类型:

程序清单:codes\04\4.11\imported.xsd

alt

上面的Schema中定义了一个age_Type类型,而且定义了目标命名空间http://www.crazyit.org,这意味着导入该Schema的Schema不能使用该命名空间作为其自身的命名空间。

下面的Schema使用<import…/>元素导入了上面的Schema文档:

程序清单:codes\04\4.11\import.xsd

alt

上面的Schema的目标命名空间是http://www.crazyit.org/schema,与被导入的Schema的目标命名空间不同,这就满足了使用<import.../>元素导入另一个Schema的前提条件。上面的Schema的①号代码指定了http://www.crazyit.org命名空间的前缀是crazyit,因此该Schema中使用age_Type时指定了crazyit前缀。因为在使用被导入Schema里的Schema组件时,必须使用命名空间前缀作为限定,除非被导入Schema没有目标命名空间。