5.3 复杂类型的进一步派生

Schema没有内置任何复杂类型,所有复杂类型都由开发者派生而来。在一些复杂类型被派生完成后,开发者可再以这些复杂类型为基础,进一步派生出新的复杂类型,派生方式依然是两种:限制和扩展。

5.3.1 限制空元素类型

对空元素类型而言,元素不包含任何内容,但可以拥有属性,因此限制空元素类型时可从如下两方面入手:

alt 对指定属性增加进一步的约束。

alt 删除某个属性。

如下Schema示范了限制空元素类型:

程序清单:codes\05\5.3\restrict_empty.xsd

alt

上面的Schema中先定义了一个空元素类型book_Type,该空元素类型中定义了name和price两个属性。接着对该空元素类型进行限制:为name属性增加了额外约束,删除了price属性。对于上面的Schema,如下XML文档是有效的:

程序清单:codes\05\5.3\restrict_empty.xml

alt

从上面的介绍可以看出,对空元素类型增加限制派生出来的只能是空元素类型,只不过这种空元素类型要么具有更少的属性,要么其属性具有更严格的语义约束。

5.3.2 扩展空元素类型

扩展空元素类型可以从如下3个方面入手:

alt 为原有类型增加属性:派生出来的新类型依然是空元素类型。

alt 为原有类型增加子元素:派生出来的新类型将是包含子元素的类型。

alt 为原有类型增加mixed="true":派生出来的新类型将是混合内容类型。

如下Schema示范了这种扩展:

程序清单:codes\05\5.3\extend_empty.xsd

alt

上面的Schema中先定义了一个空元素类型book_Type,该空元素类型中定义了name和price两个属性。接着对该空元素类型进行扩展:新增了isbn属性,以及<publish-house…/>和<publish-date…/>两个子元素。对于上面的Schema,如下XML文档是有效的:

程序清单:codes\05\5.3\extend_empty.xml

alt

5.3.3 限制包含子元素的类型

限制包含子元素的类型可以从如下几个方面入手:

alt 可以对指定属性的类型增加进一步约束。

alt 可以对指定子元素的类型增加进一步约束。

alt 可以删除指定属性。

alt 可以删除指定元素。

派生类型如果需要保留基类型的子元素,则必须重新定义这些子元素,否则即可认为删除了这些子元素。如果要删除指定属性,则必须在定义该属性时使用use="prohibited"。


alt提示

以限制方式来派生新类型时,Schema对基类型中的子元素和属性的处理方式是不一样的:派生类型默认会删除基类型中的所有子元素定义,但会保留其中的所有属性定义。


程序清单:codes\05\5.3\restrict_sequence.xsd

alt

上面的Schema中先定义了一个book_Type类型,其中包含<name…/>和<price…/>两个子元素,且包含isbn和publish-date两个属性。接着通过限制该类型派生了一个restrict_book_Type类型,派生该类型时为<name…/>元素的类型增加了额外限制,删除了<price…/>子元素,为publish-date属性的类型增加了额外限制,删除了isbn属性。对于上面的Schema,如下XML文档是有效的:

程序清单:codes\05\5.3\restrict_sequence.xml

alt


alt注意

派生类型中为子元素和属性的类型增加进一步约束时,新增的约束必须在基类型的约束范围之内,不可以超出基类型里的约束。例如基类型里name属性的类型是token,则派生类型中name属性的类型只能是token类型及其增加限制后派生的新类型。对于删除子元素和属性而言,删除子元素的实质是将maxOccurs和minOccurs同时设为0,而删除属性的实质是将use属性设为prohibited。因此如果希望删除某个子元素,则基类型中定义该子元素时必须指定minOccurs="0";而如果希望删除某个属性,则基类型中定义该属性时一定不可以指定use="required"。


5.3.4 扩展包含子元素的类型

扩展包含子元素的类型可从如下两个方面入手:

alt 为基类型增加新的子元素。

alt 为基类型增加新的属性。


alt注意

扩展包含子元素的类型所派生出来的类型依然不可以是混合内容类型,也就是说不可以为派生出来的复杂类型增加mixed="true"。


当为基类型添加新的子元素时,Schema使用<sequence…/>元素来组合基类型中原有的子元素组和新增的子元素组。先看如下Schema定义:

程序清单:codes\05\5.3\extend_sequence.xsd

alt

上面的Schema中先定义了一个book_Type类型,其中包含<name…/>和<price…/>两个子元素,且包含isbn和publish-date两个属性。接着通过扩展该类型派生了一个extend_book_Type类型,派生该类型时增加了<type…/>和<targetMarket…/>两个子元素,并新增了publish-house属性。

前面已指出,Schema会以<sequence…/>元素来组合基类型中原有的子元素组和新增的子元素组,因此extend_book_Type类型的实质如下:

alt

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

程序清单:codes\05\5.3\extend_sequence.xml

alt

下面再看一个Schema示例:

程序清单:codes\05\5.3\extend_choice.xsd

alt

对于上述Schema中派生出来的extend_book_Type类型,其实质如下:

alt

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

程序清单:codes\05\5.3\extend_choice1.xml

alt

如下XML文档也是有效的:

程序清单:codes\05\5.3\extend_choice2.xml

alt

从以上介绍不难发现一点:如果基类型中使用<all…/>元素定义了子元素,则通过扩展派生出来的新类型无法添加新的子元素;即使基类型中没有使用<all…/>元素定义子元素,在通过扩展派生新类型时也不能添加由<all…/>元素包含的子元素。这一切都是因为<all…/>元素比较特殊:它不能与<sequence…/>元素嵌套使用。


alt注意

如果基类型中使用<all…/>元素定义了子元素,则通过扩展派生出来的新类型无法添加新的子元素;即使基类型中没有使用<all…/>元素定义子元素,在通过扩展派生新类型时也不能添加由<all…/>元素包含的子元素。


5.3.5 限制混合内容类型

限制混合内容类型与限制包含子元素的类型的方式基本相同。不过在这种情况下,由于基类型是混合内容类型,因此派生类型也可以是混合内容类型,当然,也可以不再是混合内容类型——如果派生类型没有指定mixed="true",则派生类型将不再是混合内容类型。

如下Schema从一个混合内容类型派生出了2个复杂类型:一个是混合内容类型,另一个是包含子元素的类型:

程序清单:codes\05\5.3\restrict_mixed.xsd

alt

alt

5.3.6 扩展混合内容类型

扩展混合内容类型与扩展包含子元素的类型的方式基本相同,只是通过扩展混合内容类型派生出来的新类型必须是混合内容类型,也就是说必须保留mixed="true"。

如下Schema示范了扩展混合内容类型:

程序清单:codes\05\5.3\extend_mixed.xsd

alt

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

程序清单:codes\05\5.3\extend_mixed.xml

alt