和簡單數據類型對應就是復雜數據類型了,XML元素的數據類型可以是簡單數據類型,也可以是復雜數據類型,而XML屬性的數據類型就只能是簡單數據類型。這篇筆記,就來學習一下XSD中的復雜數據類型了。
1、定義復雜數據類型
(1)和<simpleType>元素用來定義簡單數據類型相對應,可以使用<complexType>元素來定義復雜數據類型。其語法為:
<complexType
id=ID
name=NCName
abstract=true|false
mixed=true|false
block=(#all|extension與restriction的自由組合)
final=(#all|extension與restriction的自由組合)
any-attributes> (annotation?,(simpleContent|complexContent|((group|all|choice|sequence)?,((attribute|attributeGroup)*,anyAttribute?)))) </complexType>
其中<complexType>元素的屬性說明如下:
屬性 | 說明 |
id | 唯一標識<complexType>元素本身 |
name | 使用<complexType>元素新定義的數據類型的名稱 |
abstract | 是否為抽象的數據類型,如為抽象的,則不能在XML文檔中直接使用這種數據類型 |
mixed | 是否為混合類型,如果是混合類型,則允許同時出現字符數據和子元素 如果子元素是<simplexContent>,則不能使用該屬性 如果子元素是<complexContent>,則mixed屬性可以被<complexContet>元素的mixed屬性重寫 |
block | 防止使用指定派生類型的復雜類型來替換當前定義的復雜類型 |
final | 防止使用指定派生類型來派生新的類型 |
any attributes | 指定non-schema命名空間的任何其他屬性 |
(2)復雜數據類型只能用於元素而不能用於屬性,進一步,可以根據能應用的元素對數據類型進行分類:
- 簡單數據類型:相應的元素內容是簡單類型值,並且元素不能有屬性,使用<simpleType>定義
- 含簡單內容的復雜數據類型:相應的元素內容是簡單類型值,但元素具有屬性,使用<complexType> <simpleContent> </simpleContent> </complexType>定義,其中<simpleContent>元素的語法如下:
<simpleContent id=ID any-attributes> (annotation?,(restriction|extension)) </simpleContent>
- 含復雜內容的復雜數據類型:相應的元素可以是包含子元素的元素,空元素或包含混合內容的元素,而不管元素是否有屬性,使用<complexType> <complexContent> </complexContent> </complexType>定義,其中<complexContent>元素的語法如下:
<complexContent id=ID mixed=true|false any-attributes> (annotation?,(restriction|extension)) </complexContent>
(3)在根元素<schema>下定義的復雜數據類型為全局的,此時name屬性是必須的,否則為局部的。
(4)final屬性用於指定不能以那種方式派生新類型,可以取的值有#all,extension和restriction的自由組合,默認值為根元素<schema>的finalDefault屬性值。這個屬性其實和<simplexType>的final屬性類似,只是<simplexType>的final屬性取值可以是#all或restriction、list、union的自由組合。
(5)block屬性指定不能使用指定方式派生出來的類型來替換所定義的類型,可以取的值和final相同,默認值為根元素<schema>的blockDefault屬性值。
2、定義元素
(1)在定義復雜數據類型時,需要定義子元素和屬性,那么怎么定義元素呢?在XSD中,可以使用<element>元素來定義元素,其語法如下:
<element
id=ID
name=NCName
ref=QName
type=QName
substitutionGroup=QName
default=string
fixed=string
form=qualified|unqualified
maxOccurs=nonNegativeInteger|unbounded
minOccurs=nonNegativeInteger
nillable=true|false
abstract=true|false
block=(#all|extension、restriction和substitution的自由組合)
final=(#all|extension和restriction的自由組合)
any-attributes> (annotation?,((simpleType|complexType)?,(unique|key|keyref)*) </element>
其中element元素的各屬性如下表:
屬性 | 說明 |
id | 唯一標識<element>元素 |
name | 新定義元素的名稱,根元素<schema>下定義時為必須屬性 |
ref | 對另一個元素的引用,可包含一個命名空間前綴 |
type | 數據類型,可以是內建數據類型、simpleType或complexType定義的類型 |
substitutionGroup | 可用來替代該元素的元素名稱,必須具有相同的類型或從其派生類型 |
default | 默認值,元素內容是簡單類型或textOnly時使用 |
fixed | 固定值,元素內容是簡單類型或textOnly時使用,默認值default和固定值fixed不能同時指定 |
form | 是否通過命名空間前綴限定該元素,默認值為<schema>元素的elementFormDefault屬性值 |
maxOccurs | 在父元素中出現的最大次數,非負整數或無限制(unbounded),默認值為1 |
minOccurs | 在父元素中出現的最少次數,必須小於或等於maxOccurs,默認值為1 |
nillable | 是否可以將顯示的零值分配給該元素,默認為false,如果為true,則在XML文檔中可以設定該元素的nil屬性為true |
abstract | 是否為抽象元素,如為抽象元素,則不能直接在XML文檔中使用 |
block | 阻止使用指定派生方式的元素來替換當前元素 |
final | 設置element元素上final屬性的默認值 |
any attributes | 指定non-schema命名空間的任何其他屬性 |
其中父元素是根元素<schema>時,不能使用ref、form、maxOccurs、minOccurs等屬性,而substitutionGroup、final等屬性則只能使用在父元素為根元素的情況下。
(2)可以通過<group>元素將一組屬性定義在一起,然后在其它需要元素的地方用元素組的引用就可以了。語法如下:
<group
id=ID
name=NCName
ref=QName
maxOccurs=nonNegativeInteger|unbounded
minOccurs=nonNegativeInteger
any-attributes> (annotation?,(all|choice|sequence)?) </group>
看一個例子:
<xs:group name="personGroup"> <xs:sequence> <xs:element name="firstname" type="xs:string"/> <xs:element name="lastname" type="xs:string"/> </xs:sequence> </xs:group> <xs:element name="person" type="personType"/> <xs:complexType name="personType"> <xs:sequence> <xs:group ref="personGroup"/> <xs:element name="country" type="xs:string"/> </xs:sequence> </xs:complexType>
這里涉及到了三種順序指示器,用於定義元素的順序:
- all:子元素能以任意順序出現,但是每個子元素必須只出現一次,這個時候可以把minOccurs設置為0或1,並且只能把maxOccurs設置為1
- choice:子元素是互斥的關系,只能出現其中之一
- sequence:子元素必須按照指定的順序出現
(3)元素通配符
在某些情況下,如果無法確定指定元素還需要包含哪些子元素、哪些屬性,這時候可使用通配符。XSD中使用<any>元素作為元素通配符,表示任何元素,即<any>元素出現的位置可以使用任何元素代替,其語法格式如下:
<any id=ID maxOccurs=nonNegativeInteger|unbounded minOccurs=nonNegativeInteger namespace=namespace processContents=lax|skip|strict any-attributes> (annotation?) </any>
<any>元素的屬性:
屬性 | 說明 | 取值/取值類型 | 默認值 |
id | 唯一標識該元素 | ID類型 | |
maxOccurs | 該元素最多可出現的次數 | 非負整數或unbounded | 1 |
minOccurs | 該元素最少可出現的次數 | 非負整數,必須小於maxOccurs | 1 |
namespace | 指定可代替該通配符的元素必須來自哪個空間 |
|
|
processContents | 指定應用程序或XML處理器如何對替換元素進行驗證 |
|
strict |
(4)元素替換
XSD還提供了一種機制,允許使用一個元素替換另一個元素,如果想定義某個元素可替換另一個元素,可以為該元素增加substitutionGroup屬性,其值就是該元素想替換的元素的名字。使用元素替換需注意兩點:
- 替換元素和被替換元素必須以全局元素的形式來聲明
- 替換元素和被替換元素要么有相同的數據類型,要么替換元素類型是被替換元素類型的派生類型
另外,
- 可以使用final屬性來阻止自己被指定派生類型替換
- 可以使用block屬性來阻止指定派生類型的替換
3、定義屬性
定義屬性和定義元素是完全統一的,只是定義屬性使用<attribute>元素,其語法格式如下:
<attribute
id=ID
name=NCName
ref=QName
type=QName
default=string
fixed=string
form=qualified|unqualified
uese=optional|prohibited|required
any-attributes> (annotation?,(simpleType?)) </attribute>
(1)<attribute>元素的屬性基本和<element>元素相同,不同的是form屬性的默認值是根元素<schema>的attributeFormDefault屬性的值。另外,use屬性是<element>所沒有的,它表示怎么使用這個屬性,可以取的值有:
- optional:屬性是可選的,並且可以具有指定數據類型的任意值
- prohibited:不能使用屬性(既然不能使用,為何還要定義?主要是在派生新類型使用,用來刪除原類型的某個屬性)
- required:必須的屬性,此時不能指定default和fixed
(2)在根元素<schema>下定義的屬性稱之為全局屬性,其它的屬性則可以通過<attribute>元素的ref屬性來引用全局屬性;也可以直接將<attribute>放在<complexType>元素內部定義屬性。
(3)類似<group>元素定義元素組,還可以使用<attributeGroup>元素定義屬性組,其語法格式如下:
<attributeGroup id=ID name=NCName ref=QName any-attributes> (annotation?,((attribute|attributeGroup)*,anyAttribute?)) </attributeGroup>
(4)屬性通配符
類似於元素通配符,可以使用<anyAttribute>表示屬性通配符,其語法格式如下:
<anyAttribute id=ID namespace=namespace processContents=lax|skip|strict any-attributes> (annotation?) </anyAttribute>
其中屬性含義與元素通配符<any>相同。
4、再看看怎么派生復雜數據類型
知道怎么定義元素和屬性之后,就可以進一步看怎么定義復雜數據類型了,總的來說,定義復雜數據類型需要弄清兩個問題:第一個問題是基類型的問題——定義復雜數據類型的基礎是哪個類型?第二個問題就是派生方式的問題——派生復雜數據類型可以使用限制<restriction>和擴展<extension>兩種方式。
(1)基類型
- anyType類型:和DTD中的ANY類似,XSD中也有一個anyType類型,這種類型的元素沒有任何限制,可以包含子元素,可以包含字符串內容,還可以添加任何屬性(但這些屬性需要在XSD文件中定義過),anyType類型是所有簡單類型和所有復雜類型的基類型,通常用於派生新的類型,而不是直接用來定義元素。
- 簡單類型
- 含簡單內容的復雜類型:元素內容是簡單類型值,但元素包括屬性
- 空元素類型:用於定義內容為空或空字符串的元素,但是該元素可以接受屬性。定義空元素類型有兩種方式:
- 擴展長度為0的字符串:如果該元素不需要包含屬性,那么直接使用長度為0的字符串類型定義該元素即可
- 限制anyTye:限制anyType時不定義任何子元素,只定義所需屬性即可
<xs:simpleType name="emptyString"> <xs:restriction base="xs:string"> <xs:maxLength value="0"/> </xs:restriction> </xs:simpleType> <xs:element name="book"> <xs:complexType> <xs:simpleContent> <!--以空字符串為基礎派生新的復雜類型--> <xs:extension base="emptyString"> <!--添加一個屬性--> <xs:attribute name="name" type="xs:token"/> </xs:extension> </xs:simpleContent> </xs:complexType> </xs:element> <xs:element name="book2"> <xs:complexType> <!--不指定子元素,即定義了一個空元素--> <!--添加一個屬性--> <xs:attribute nae="name" type="xs:token"/> </xs:complexType> </xs:element>
- 包含子元素的類型
- 混合內容類型
(2)派生方式
- 限制<restriction>
- 擴展<extension>
下面是我從這基類型和派生方式兩個維度統計的一個列表:
基類型 | 派生方式 | 定義時使用的XSD元素 | 說明 |
anyType類型 | 限制 | <complexType><complexContent><restriction> |
因為anyType只能限制,不能擴展,所以可以省略<complexContent><restriction>元素, 而直接在<complexType>內部使用<all>|<choice>|<sequence>等元素 |
擴展 |
|
anyType類型已經沒有任何限制了,所以也就不需要再擴展了 |
|
簡單類型 | 限制 | <simpleType> |
限制簡單類型最終結果也是一個簡單類型,因此使用<simpleType>元素 |
擴展 | <complexType><simpleContent><extension> |
可以通過添加屬性或屬性組派生復雜數據類型 | |
包含簡單內容的復雜類型 | 限制 | <complexType><simpleContent><restriction> |
|
擴展 | <complexType><simpleContent><extension> |
添加屬性 | |
空元素類型 | 限制 | <complexType><complexContent><restriction> |
|
擴展 | <complexType><complexContent><extension> |
|
|
包含子元素的類型 | 限制 | <complexType><complexContent><restriction> |
|
擴展 | <complexType><complexContent><extension> |
|
|
混合內容類型 | 限制 | <complexType><complexContent><restriction> |
限制混合內容類型的方式和限制包含子元素的類型基本相同 |
擴展 | <complexType><complexContent><extension> |
擴展混合內容類型的方式和擴展包含子元素的類型基本相同,但是必須保留mixed="true" |
派生類型的另外一種用法:
假設在XSD中定義了元素<book>,其類型是book_type(包含一個name屬性),同時還定義了book_type的派生數據類型extended_book_type(在book_type基礎上添加就價格price屬性),這種情況下,在實際XML文檔中, 可以以如下兩種方式使用<book>元素:
<!--1。第一種方式,book元素實際類型為book_type類型--> <book name="example1"/> <!--2。第二種方式,使用xsi:type指定book元素的實際類型為extended_book_type,這里xsi為命名空間http://www.w3.org/2001/XMLSchema-instance對應的前綴--> <book name="example2" xsi:type="extended_book_type" price="100"/>
5、一致性約束
定義元素還可以指定3種類型的約束:
- key約束:相當於DB里面的主鍵約束,要求指定內容必須存在而且唯一
- keyref約束:相當於DB里面的外鍵約束,要求指定內容的值必須使用refer屬性引用另一個key約束或unique約束
- unique約束:相當於DB里面的唯一約束,要求指定內容必須唯一,但可以不存在
這3個一致性約束都只能在<element>元素內定義,且只能在<element>元素的最后面定義。
在DB中定義約束時,不僅需要指定使用哪類約束,還需要定義應該對哪些字段應用約束,在XSD中定義一致性約束也完全類似,也需要指定該約束將對哪些部分起作用,因此需要在約束內使用如下兩個子元素:
- <selector>:需指定一個xpath屬性,其值是一個XPath表達式,用來確定一個元素范圍,在一次約束定義中,<selector>必須且只能出現一次
- <field>:需要指定一個xpath屬性,其值是一個XPath表達式,在一次約束定義中,<field>至少要出現一次,也可以出現多次
這兩個元素的含義是:在<selector>元素的XPath表達式表示的范圍內,<field>元素的XPath表達式所表示的內容必須遵守一致性約束,如果有多個<field>元素,則它們的XPath表達式內容的組合必須遵守一致性約束,當XPath表達式所表示的內容無需遵守,這個概念相當於DB中的多列組合約束。
看下例子:
<xs:element name="book-list"> <xs:complexType> <xs:sequence> <xs:element ref="book" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> <!--定義key約束,只在book-list之內有效--> <xs:key name="nameKey"> <!--在當前上下文的book元素之內(即book-list/book之內)--> <xs:selector xpath="book"/> <!--指定book-list/book元素之內的name元素的值必須存在且唯一--> <xs:field xpath="name"/> </xs:key> </xs:element>
6、定義符號
最后看一下和DTD中對應的定義符號的用法,在XSD中使用<notation>元素定義符號,用來標識XML文檔中的外部數據,該元素可接受的屬性有:
- id:指定該符號的唯一標識,通常無需指定
- name:指定該符號的名稱,是一個必填屬性,而且該名稱在整個XSD內必須是唯一的
- public:指定該符號所標識數據的外部格式或對應處理程序,必填屬性,相當於DTD中<!NOTATION>中PUBLIC的作用
- system:指定該符號所標識數據的外部格式或對應處理程序,可選屬性,相當於DTD中<!NOTATION>中SYSTEM的作用