5.6 元素替换

Schema还提供了一种机制,允许使用一个元素替换另一个元素。如果想定义某个元素可替换另一个元素,可为该元素增加substitutionGroup属性,其值就是该元素想替换的元素的名字。

使用元素替换要注意如下几点:

alt 替换元素和被替换元素都必须以全局元素的形式来声明。

alt 替换元素与被替换元素要么有相同的数据类型,要么替换元素类型是被替换元素类型的派生类型。

在Schema中定义了支持元素替换之后,就可以在XML文档中使用替换元素来代替被替换元素了。如下Schema中定义了支持元素替换:

程序清单:codes\05\5.6\substitutionGroup.xsd

alt

上面的Schema中定义了<book…/>和<game…/>两个全局元素,它们可用于替换<item…/>全局元素,而且<book…/>和<game…/>元素的类型是<item…/>元素类型的派生类型。对于上面的Schema,如下XML文档是有效的:

程序清单:codes\05\5.6\substitutionGroup.xml

alt

由上面的示例可以看出,通过使用元素替换,Schema能以更灵活的方式来定义XML的语义约束。

5.6.1 阻止自己被替换

通过上面的Schema文档可以看出,在定义一个全局元素时,该元素无法知道自己是否会被替换,这当然为Schema定义增加了一定的灵活性,但也引入了一些未知的风险。如果想在定义某个全局元素时阻止自己被替换,可以为<element…/>元素增加final属性,其值可以是:

alt #all:该元素绝不会被其他元素替换。

alt extension:阻止以扩展该元素类型的方式派生出来的新类型的元素替换自己。

alt restriction:阻止以限制该元素类型的方式派生出来的新类型的元素替换自己。

alt extension和restriction的组合:阻止以限制和扩展该元素类型的方式派生出来的新类型的元素替换自己。

光看上面的解释,读者可能会有点迷惑,这段文字解释起来确实有点费劲。看下列代码就比较容易理解了,下面的Schema中定义了<item…/>全局元素,还定义了<book…/>和<game…/>两个子元素:

程序清单:codes\05\5.6\final.xsd

alt

上面的Schema中定义<item…/>元素时指定了final="restriction",这意味着该元素不能被通过限制其元素类型派生出来的新类型的元素所替换,因此上面的<game…/>元素试图替换<item…/>元素是不被允许的。

除此之外,Schema允许将<element…/>元素里的final属性替换成block,block属性能接受的属性值与final属性基本一样,区别是通过block属性阻止自己被替换只对XML文档有效,对Schema则不会有任何影响。如果将上面的Schema中的final="restriction"改为block="restriction",则上面的Schema是有效的,但XML文档中依然不能使用<game…/>元素来替换<item…/>元素。也就是说,如下XML文档才有效:

程序清单:codes\05\5.6\element_block.xml

alt

5.6.2 阻止指定派生类型的替换

在Schema中定义元素替换时,被替换元素只能被相应类型的派生类型的元素所替换,因此Schema允许在定义<complexType…/>元素时指定block属性,该属性能接受的属性值与<element…/>元素里final属性能接受的属性值大致相同。不同的是,在为<complexType…/>元素指定block属性之后,该block属性是对该复杂类型生效。也就是说,该类型的所有元素都不会被替换。

如下Schema定义了一个item_Type,并使用该类型定义了2个元素:<item…/>和<action…/>,由于定义item_Type类型时指定了block="#all",因此<item…/>和<action…/>元素都不能被替换:

程序清单:codes\05\5.6\complexType_block.xsd

alt

上面的Schema中为item_Type类型指定了block="#all",并使用该类型定义了<item…/>和<action…/>两个元素,后面又定义了<book…/>元素试图代替<item…/>元素,定义了<game…/>元素试图代替<action…/>元素,这份Schema代码依然是有效的。因为block="#all"仅仅阻止了在XML文档中使用<book…/>元素替换<item…/>元素,使用<game…/>元素替换<action…/>元素,并不会检查Schema里的元素。

对于上面的Schema,如下XML文档是有效的:

程序清单:codes\05\5.6\complexType_block.xml

alt