XSD 复杂的类型
什么是复合元素?
复合元素指包含其他元素及/或属性的 XML 元素。
有四种类型的复合元素:
- 空元素
- 包含其他元素的元素
- 仅包含文本的元素
- 包含元素和文本的元素
注释:上述元素均可包含属性!
复合元素的例子
复合元素,"product",是空的:
<product pid="1345"/>
复合元素,"employee",仅包含其他元素:
<employee> <firstname>John</firstname> <lastname>Smith</lastname> </employee>
复合元素,"food",仅包含文本:
<food type="dessert">Ice cream</food>
复合元素,"description",包含元素和文本:
<description> It happened on <date lang="norwegian">03.03.99</date> .... </description>
如何定义复合元素?
请看这个复合 XML 元素,"employee",仅包含其他元素:
<employee> <firstname>John</firstname> <lastname>Smith</lastname> </employee>
在 XML Schema 中,我们有两种方式来定义复合元素:
1. 通过命名此元素,可直接对"employee"元素进行声明,就像这样:
<xs:element name="employee"> <xs:complexType> <xs:sequence> <xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element>
假如您使用上面所描述的方法,那么仅有 "employee" 可使用所规定的复合类型。请注意其子元素,"firstname" 以及 "lastname",被包围在指示器 <sequence>中。这意味着子元素必须以它们被声明的次序出现。您会在 XSD 指示器 这一节学习更多有关指示器的知识。
2. "employee" 元素可以使用 type 属性,这个属性的作用是引用要使用的复合类型的名称:
<xs:element name="employee" type="personinfo"/> <xs:complexType name="personinfo"> <xs:sequence> <xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/> </xs:sequence> </xs:complexType>
如果您使用了上面所描述的方法,那么若干元素均可以使用相同的复合类型,比如这样:
<xs:element name="employee" type="personinfo"/> <xs:element name="student" type="personinfo"/> <xs:element name="member" type="personinfo"/> <xs:complexType name="personinfo"> <xs:sequence> <xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/> </xs:sequence> </xs:complexType>
您也可以在已有的复合元素之上以某个复合元素为基础,然后添加一些元素,就像这样:
<xs:element name="employee" type="fullpersoninfo"/> <xs:complexType name="personinfo"> <xs:sequence> <xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/> </xs:sequence> </xs:complexType> <xs:complexType name="fullpersoninfo"> <xs:complexContent> <xs:extension base="personinfo"> <xs:sequence> <xs:element name="address" type="xs:string"/> <xs:element name="city" type="xs:string"/> <xs:element name="country" type="xs:string"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>
复合空元素:
一个空的 XML 元素:
<product prodid="1345" />上面的 "product" 元素根本没有内容。为了定义无内容的类型,我们就必须声明一个在其内容中只能包含元素的类型,但是实际上我们并不会声明任何元素,比如这样:
<xs:element name="product"> <xs:complexType> <xs:complexContent> <xs:restriction base="xs:integer"> <xs:attribute name="prodid" type="xs:positiveInteger"/> </xs:restriction> </xs:complexContent> </xs:complexType> </xs:element>在上面的例子中,我们定义了一个带有复合内容的复合类型。complexContent 元素给出的信号是,我们打算限定或者拓展某个复合类型的内容模型,而 integer 限定则声明了一个属性但不会引入任何的元素内容。
不过,也可以更加紧凑地声明此 "product" 元素:
<xs:element name="product"> <xs:complexType> <xs:attribute name="prodid" type="xs:positiveInteger"/> </xs:complexType> </xs:element>或者您可以为一个 complexType 元素起一个名字,然后为 "product" 元素设置一个 type 属性并引用这个 complexType 名称(通过使用此方法,若干个元素均可引用相同的复合类型):
<xs:element name="product" type="prodtype"/> <xs:complexType name="prodtype"> <xs:attribute name="prodid" type="xs:positiveInteger"/> </xs:complexType>复合类型仅包含元素
XML 元素,"person",仅包含其他的元素:
<person> <firstname>John</firstname> <lastname>Smith</lastname> </person>您可在 schema 中这样定义 "person" 元素:
<xs:element name="person"> <xs:complexType> <xs:sequence> <xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:element>请留意这个 <xs:sequence>。它意味着被定义的元素必须按上面的次序出现在 "person" 元素中。
或者您可以为 complexType 元素设定一个名称,并让 "person" 元素的 type 属性来引用此名称(如使用此方法,若干元素均可引用相同的复合类型):
<xs:element name="person" type="persontype"/> <xs:complexType name="persontype"> <xs:sequence> <xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/> </xs:sequence> </xs:complexType>仅含文本的复合元素
此类型仅包含简易的内容(文本和属性),因此我们要向此内容添加 simpleContent 元素。当使用简易内容时,我们就必须在 simpleContent 元素内定义扩展或限定,就像这样:
<xs:element name="某个名称"> <xs:complexType> <xs:simpleContent> <xs:extension base="basetype"> .... .... </xs:extension> </xs:simpleContent> </xs:complexType> </xs:element>或者:
<xs:element name="某个名称"> <xs:complexType> <xs:simpleContent> <xs:restriction base="basetype"> .... .... </xs:restriction> </xs:simpleContent> </xs:complexType> </xs:element>提示:请使用 extension 或 restriction 元素来扩展或限制元素的基本简易类型。
这里有一个 XML 元素的例子,"shoesize",其中仅包含文本:
<shoesize country="france">35</shoesize>下面这个例子声明了一个复合类型,其内容被定义为整数值,并且 "shoesize" 元素含有名为 "country" 的属性:
<xs:element name="shoesize"> <xs:complexType> <xs:simpleContent> <xs:extension base="xs:integer"> <xs:attribute name="country" type="xs:string" /> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:element>我们也可为 complexType 元素设定一个名称,并让 "shoesize" 元素的 type 属性来引用此名称(通过使用此方法,若干元素均可引用相同的复合类型):
<xs:element name="shoesize" type="shoetype"/> <xs:complexType name="shoetype"> <xs:simpleContent> <xs:extension base="xs:integer"> <xs:attribute name="country" type="xs:string" /> </xs:extension> </xs:simpleContent> </xs:complexType>带有混合内容的复合类型
XML 元素,"letter",含有文本以及其他元素:
<letter> Dear Mr.<name>John Smith</name>. Your order <orderid>1032</orderid> will be shipped on <shipdate>2001-07-13</shipdate>. </letter>下面这个 schema 声明了这个 "letter" 元素:
<xs:element name="letter"> <xs:complexType mixed="true"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="orderid" type="xs:positiveInteger"/> <xs:element name="shipdate" type="xs:date"/> </xs:sequence> </xs:complexType> </xs:element>注释:为了使字符数据可以出现在 "letter" 的子元素之间,mixed 属性必须被设置为 "true"。<xs:sequence> 标签 (nam、orderid 以及 shipdate ) 意味着被定义的元素必须依次出现在 "letter" 元素内部。
我们也可以为 complexType 元素起一个名字,并让 "letter" 元素的 type 属性引用 complexType 的这个名称(通过这个方法,若干元素均可引用同一个复合类型):
<xs:element name="letter" type="lettertype"/> <xs:complexType name="lettertype" mixed="true"> <xs:sequence> <xs:element name="name" type="xs:string"/> <xs:element name="orderid" type="xs:positiveInteger"/> <xs:element name="shipdate" type="xs:date"/> </xs:sequence> </xs:complexType>通过指示器,我们可以元素在文档中被使用的方式。
指示器
有七种指示器:
Order 指示器:
- All
- Choice
- Sequence
Occurrence 指示器:
- maxOccurs
- minOccurs
Group 指示器:
- Group name
- attributeGroup name
Order 指示器
Order 指示器用于定义元素的顺序。
All 指示器
<all> 指示器可规定子元素以何种顺序出现,以及每个子元素须出现几次:
<xs:element name="person"> <xs:complexType><xs:all><xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/></xs:all></xs:complexType> </xs:element>注释:当使用 <all> 指示器时,你可以把 <minOccurs> 设置为 0 或者 1,并仅可把 <maxOccurs> 指示器设置为 1(稍后将讲解 <minOccurs> 以及 <maxOccurs>)。
Choice 指示器
<choice> 指示器可规定可出现某个子元素或者可出现另外一个子元素(非此即彼):
<xs:element name="person"> <xs:complexType><xs:choice><xs:element name="employee" type="employee"/> <xs:element name="member" type="member"/></xs:choice></xs:complexType> </xs:element>Sequence 指示器
<sequence> 可规定子元素必须按照特定的顺序出现:
<xs:element name="person"> <xs:complexType><xs:sequence><xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/></xs:sequence></xs:complexType> </xs:element>Occurrence 指示器
Occurrence 指示器用来定义某个元素出现的频率。
注释:对于所有的 "Order" 和 "Group" 指示器(any、all、choice、sequence、group name 以及 group reference),其中的 maxOccurs 以及 minOccurs 的默认值均为 1。
maxOccurs 指示器
<maxOccurs> 指示器可规定某个元素可出现的最大次数:
<xs:element name="person"> <xs:complexType> <xs:sequence> <xs:element name="full_name" type="xs:string"/> <xs:element name="child_name" type="xs:string"maxOccurs="10"/> </xs:sequence> </xs:complexType> </xs:element>上面的例子表明,子元素 "child_name" 可在 "person" 元素中最少出现一次(其中 minOccurs 的默认值是 1),最多出现 10 次。
minOccurs 指示器
<minOccurs> 指示器可规定某个元素能够出现的最小次数:
<xs:element name="person"> <xs:complexType> <xs:sequence> <xs:element name="full_name" type="xs:string"/> <xs:element name="child_name" type="xs:string" maxOccurs="10"minOccurs="0"/> </xs:sequence> </xs:complexType> </xs:element>上面的例子表明,子元素 "child_name" 可在 "person" 元素中出现最少 0 次,最多出现 10 次。
提示:如需使某个元素的出现次数不受限制,请使用 maxOccurs="unbounded" 这个声明:
一个实际的例子:
名为 "Myfamily.xml" 的 XML 文件:
<?xml version="1.0" encoding="ISO-8859-1"?> <persons xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="family.xsd"> <person> <full_name>Hege Refsnes</full_name> <child_name>Cecilie</child_name> </person> <person> <full_name>Tove Refsnes</full_name> <child_name>Hege</child_name> <child_name>Stale</child_name> <child_name>Jim</child_name> <child_name>Borge</child_name> </person> <person> <full_name>Stale Refsnes</full_name> </person> </persons>上面这个 XML 文件含有一个名为 "persons" 的根元素。在这个根元素内部,我们定义了三个 "person" 元素。每个 "person" 元素必须含有一个 "full_name" 元素,同时它可以包含多至 5 个 "child_name" 元素。
这是schema文件"family.xsd":
<?xml version="1.0" encoding="ISO-8859-1"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:element name="persons"> <xs:complexType> <xs:sequence> <xs:element name="person" maxOccurs="unbounded"> <xs:complexType> <xs:sequence> <xs:element name="full_name" type="xs:string"/> <xs:element name="child_name" type="xs:string"minOccurs="0" maxOccurs="5"/> </xs:sequence> </xs:complexType> </xs:element> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>Group 指示器
Group 指示器用于定义相关的数批元素。
元素组
元素组通过 group 声明进行定义:
<xs:group name="组名称"> ... </xs:group>您必须在 group 声明内部定义一个 all、choice 或者 sequence 元素。下面这个例子定义了名为 "persongroup" 的 group,它定义了必须按照某种精确的顺序出现的一组元素:
<xs:group name="persongroup"> <xs:sequence> <xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/> <xs:element name="birthday" type="xs:date"/> </xs:sequence> </xs:group>在您把 group 定义完毕以后,就可以在另一个定义中引用它了:
<xs:groupname="persongroup"> <xs:sequence> <xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/> <xs:element name="birthday" type="xs:date"/> </xs:sequence> </xs:group> <xs:element name="person" type="personinfo"/> <xs:complexType name="personinfo"> <xs:sequence><xs:group ref="persongroup"/><xs:element name="country" type="xs:string"/> </xs:sequence> </xs:complexType>属性组
属性组通过 attributeGroup 声明来进行定义:
<xs:attributeGroup name="组名称"> ... </xs:attributeGroup>下面这个例子定义了名为 "personattrgroup" 的一个属性组:
<xs:attributeGroup name="personattrgroup"> <xs:attribute name="firstname" type="xs:string"/> <xs:attribute name="lastname" type="xs:string"/> <xs:attribute name="birthday" type="xs:date"/> </xs:attributeGroup>在您已定义完毕属性组之后,就可以在另一个定义中引用它了,就像这样:
<xs:attributeGroupname="personattrgroup"> <xs:attribute name="firstname" type="xs:string"/> <xs:attribute name="lastname" type="xs:string"/> <xs:attribute name="birthday" type="xs:date"/> </xs:attributeGroup> <xs:element name="person"> <xs:complexType><xs:attributeGroup ref="personattrgroup"/></xs:complexType> </xs:element><any> 元素
<any> 元素使我们有能力通过未被 schema 规定的元素来拓展 XML 文档!
下面这个例子是从名为 "family.xsd" 的 XML schema 中引用的片段。它展示了一个针对 "person" 元素的声明。通过使用 <any> 元素,我们可以通过任何元素(在 <lastname> 之后)扩展 "person" 的内容:
<xs:element name="person"> <xs:complexType> <xs:sequence> <xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/><xs:any minOccurs="0"/></xs:sequence> </xs:complexType> </xs:element>现在,我们希望使用 "children" 元素来扩展 "person" 元素。这此种情况下我们就可以这么做,即使以上这个 schema 的作者没有声明任何 "children" 元素。
请看这个 schema 文件,名为 "children.xsd":
<?xml version="1.0" encoding="ISO-8859-1"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3schools.com" xmlns="http://www.w3schools.com" elementFormDefault="qualified"> <xs:element name="children"> <xs:complexType> <xs:sequence> <xs:element name="childname" type="xs:string" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> </xs:schema>下面这个 XML 文件(名为 "Myfamily.xml"),使用了来自两个不同的 schema 中的成分,"family.xsd" 和 "children.xsd":
<?xml version="1.0" encoding="ISO-8859-1"?> <persons xmlns="http://www.microsoft.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:SchemaLocation="http://www.microsoft.com family.xsd http://www.w3schools.com children.xsd"> <person> <firstname>Hege</firstname> <lastname>Refsnes</lastname> <children> <childname>Cecilie</childname> </children> </person> <person> <firstname>Stale</firstname> <lastname>Refsnes</lastname> </person> </persons>上面这个 XML 文件是有效的,这是由于 schema "family.xsd" 允许我们通过在 "lastname" 元素后的可选元素来扩展 "person" 元素。
<any> 和 <anyAttribute> 均可被用来制作可扩展的文档!它们使文档有能力包含未在主 XML schema 中被声明过的附加元素。
<anyAttribute> 元素
<anyAttribute> 元素使我们有能力通过未被 schema 规定的属性来扩展XML文档!
下面的例子是来自名为 "family.xsd" 的 XML schema 的一个片段。它为我们展示了针对 "person" 元素的一个声明。通过使用 <anyAttribute> 元素,我们就可以向 "person" 元素添加任意数量的属性:
<xs:element name="person"> <xs:complexType> <xs:sequence> <xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/> </xs:sequence><xs:anyAttribute/></xs:complexType> </xs:element>现在,我们希望通过 "gender" 属性来扩展 "person" 元素。在这种情况下我们就可以这样做,即使这个 schema 的作者从未声明过任何 "gender" 属性。
请看这个 schema 文件,名为 "attribute.xsd":
<?xml version="1.0" encoding="ISO-8859-1"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.w3schools.com" xmlns="http://www.w3schools.com" elementFormDefault="qualified"> <xs:attribute name="gender"> <xs:simpleType> <xs:restriction base="xs:string"> <xs:pattern value="male|female"/> </xs:restriction> </xs:simpleType> </xs:attribute> </xs:schema>下面这个 XML(名为 "Myfamily.xml"),使用了来自不同 schema 的成分,"family.xsd" 和 "attribute.xsd":
<?xml version="1.0" encoding="ISO-8859-1"?> <persons xmlns="http://www.microsoft.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:SchemaLocation="http://www.microsoft.com family.xsd http://www.w3schools.com attribute.xsd"> <person gender="female"> <firstname>Hege</firstname> <lastname>Refsnes</lastname> </person> <person gender="male"> <firstname>Stale</firstname> <lastname>Refsnes</lastname> </person> </persons>上面这个 XML 文件是有效的,这是因为 schema "family.xsd" 允许我们向 "person" 元素添加属性。
<any> 和 <anyAttribute> 均可被用于制作可扩展的文档!它们使文档有能力包含未在主 XML schema 中被声明过的附加元素。
元素替换
让我们举例说明:我们的用户来自英国和挪威。我们希望有能力让用户选择在 XML 文档中使用挪威语的元素名称还是英语的元素名称。
为了解决这个问题,我们可以在 XML schema 中定义一个 substitutionGroup。首先,我们声明主元素,然后我们会声明次元素,这些次元素可声明它们能够替换主元素。
<xs:element name="name" type="xs:string"/> <xs:element name="navn"substitutionGroup="name"/>在上面的例子中,"name" 元素是主元素,而 "navn" 元素可替代 "name" 元素。
请看某个 XML schema 的片段:
<xs:element name="name" type="xs:string"/> <xs:element name="navn" substitutionGroup="name"/> <xs:complexType name="custinfo"> <xs:sequence> <xs:element ref="name"/> </xs:sequence> </xs:complexType> <xs:element name="customer" type="custinfo"/> <xs:element name="kunde" substitutionGroup="customer"/>有效的 XML 文档类似这样(根据上面的 schema):
<customer> <name>John Smith</name> </customer>或类似这样:
<kunde> <navn>John Smith</navn> </kunde>阻止元素替换
为防止其他的元素替换某个指定的元素,请使用 block 属性:
<xs:element name="name" type="xs:string"block="substitution"/>请看某个 XML schema 的片段:
<xs:element name="name" type="xs:string" block="substitution"/> <xs:element name="navn" substitutionGroup="name"/> <xs:complexType name="custinfo"> <xs:sequence> <xs:element ref="name"/> </xs:sequence> </xs:complexType> <xs:element name="customer" type="custinfo" block="substitution"/> <xs:element name="kunde" substitutionGroup="customer"/>合法的 XML 文档应该类似这样(根据上面的 schema):
<customer> <name>John Smith</name> </customer>但是下面的文档不再合法:
<kunde> <navn>John Smith</navn> </kunde>使用 substitutionGroup
可替换元素的类型必须和主元素相同,或者从主元素衍生而来。假如可替换元素的类型与主元素的类型相同,那么您就不必规定可替换元素的类型了。
请注意,substitutionGroup 中的所有元素(主元素和可替换元素)必须被声明为全局元素,否则就无法工作!
什么是全局元素(Global Elements)?
全局元素指 "schema" 元素的直接子元素!本地元素(Local elements)指嵌套在其他元素中的元素。

浙公网安备 33010602011771号