和單一資料型別對應就是複雜資料類型了,XML元素的資料類型可以是單一資料型別,也可以是複雜資料類型,而XML屬性的資料類型就只能是單一資料型別。這篇筆記,就來學習一下XSD中的複雜資料類型了。
1、定義複雜資料類型
(1)和<simpleType>元素用來定義單一資料型別相對應,可以使用<complexType>元素來定義複雜資料類型。其文法為:
id name abstract mixed block final any-attributes
其中<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>元素的文法如下:
- 含複雜內容的複雜資料類型:相應的元素可以是包含子項目的元素,空元素或包含混合內容的元素,而不管元素是否有屬性,使用<complexType> <complexContent> </complexContent> </complexType>定義,其中<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>元素來定義元素,其文法如下:
substitutionGroup abstract
其中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>元素將一組屬性定義在一起,然後在其它需要元素的地方用元素組的引用就可以了。文法如下:
看一個例子:
這裡涉及到了三種順序指標,用於定義元素的順序:
- all:子項目能以任意順序出現,但是每個子項目必須只出現一次,這個時候可以把minOccurs設定為0或1,並且只能把maxOccurs設定為1
- choice:子項目是互斥的關係,只能出現其中之一
- sequence:子項目必須按照指定的順序出現
(3)元素萬用字元
在某些情況下,如果無法確定指定元素還需要包含哪些子項目、哪些屬性,這時候可使用萬用字元。XSD中使用<any>元素作為元素萬用字元,表示任何元素,即<any>元素出現的位置可以使用任何元素代替,其文法格式如下:
<any>元素的屬性:
| 屬性 |
說明 |
取值/取實值型別 |
預設值 |
| id |
唯一標識該元素 |
ID類型 |
|
| maxOccurs |
該元素最多可出現的次數 |
非負整數或unbounded |
1 |
| minOccurs |
該元素最少可出現的次數 |
非負整數,必須小於maxOccurs |
1 |
| namespace |
指定可代替該萬用字元的元素必須來自哪個空間 |
- ##any:任意命名空間的元素
- ##other:來自當前命名空間之外的其它任意命名空間的元素
- ##local:無命名空間限定的元素
- ##targetNamespace:當前命名空間的元素
- 命名空間URI:指定命名空間的元素
- 上面多個值的列表:值列表中的任意一個命名空間的元素
|
|
| processContents |
指定應用程式或XML處理器如何對替換元素進行驗證 |
- strict:XML處理器必須獲得由namespace指定的命名空間對應的Schema,並驗證來自該命名空間的所有元素
- lax:XML處理器嘗試擷取由namespace指定的命名空間對應的Schema,成功則驗證所有元素,否則也不報錯
- skip:XML處理器不會擷取所需命名空間,也不會進行任何驗證
|
strict |
(4)元素替換
XSD還提供了一種機制,允許使用一個元素替換另一個元素,如果想定義某個元素可替換另一個元素,可以為該元素增加substitutionGroup屬性,其值就是該元素想替換的元素的名字。使用元素替換需注意兩點:
- 替換元素和被替換元素必須以全域元素的形式來聲明
- 替換元素和被替換元素要麼有相同的資料類型,要麼替換元素類型是被替換元素類型的衍生類別型
另外,
- 可以使用final屬性來阻止自己被指定衍生類別型替換
- 可以使用block屬性來阻止指定衍生類別型的替換
3、定義屬性
定義屬性和定義元素是完全統一的,只是定義屬性使用<attribute>元素,其文法格式如下:
uese
(1)<attribute>元素的屬性基本和<element>元素相同,不同的是form屬性的預設值是根項目<schema>的attributeFormDefault屬性的值。另外,use屬性是<element>所沒有的,它表示怎麼使用這個屬性,可以取的值有:
- optional:屬性是可選的,並且可以具有指定資料類型的任意值
- prohibited:不能使用屬性(既然不能使用,為何還要定義?主要是在派生新類型使用,用來刪除原類型的某個屬性)
- required:必須的屬性,此時不能指定default和fixed
(2)在根項目<schema>下定義的屬性稱之為全域屬性,其它的屬性則可以通過<attribute>元素的ref屬性來引用全域屬性;也可以直接將<attribute>放在<complexType>元素內部定義屬性。
(3)類似<group>元素定義元素組,還可以使用<attributeGroup>元素定義屬性群組,其文法格式如下:
(4)屬性萬用字元
類似於元素萬用字元,可以使用<anyAttribute>表示屬性萬用字元,其文法格式如下:
其中屬性含義與元素萬用字元<any>相同。
4、再看看怎麼派生複雜資料類型
知道怎麼定義元素和屬性之後,就可以進一步看怎麼定義複雜資料類型了,總的來說,定義複雜資料類型需要弄清兩個問題:第一個問題是基底類型的問題——定義複雜資料類型的基礎是哪個類型?第二個問題就是派生方式的問題——派生複雜資料類型可以使用限制<restriction>和擴充<extension>兩種方式。
(1)基底類型
- anyType類型:和DTD中的ANY類似,XSD中也有一個anyType類型,這種類型的元素沒有任何限制,可以包含子項目,可以包含字串內容,還可以添加任何屬性(但這些屬性需要在XSD檔案中定義過),anyType類型是所有簡單類型和所有複雜類型的基底類型,通常用於派生新的類型,而不是直接用來定義元素。
- 簡單類型
- 含簡單內容的複雜類型:元素內容是簡單類型值,但元素包括屬性
- 空元素類型:用於定義內容為空白或Null 字元串的元素,但是該元素可以接受屬性。定義空元素類型有兩種方式:
- 擴充長度為0的字串:如果該元素不需要包含屬性,那麼直接使用長度為0的字串類型定義該元素即可
- 限制anyTye:限制anyType時不定義任何子項目,只定義所需屬性即可
(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> |
- 為原有類型增加屬性:派生出來的新類型依然是空元素類型
- 為原有類型增加子項目:派生出來的新類型將是包含子項目的類型
- 為原有類型增加mixed="true":派生出來的新類型將是混合內容類型
|
| 包含子項目的類型 |
限制 |
<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>元素:
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中的多列組合約束。
看下例子:
6、定義符號
最後看一下和DTD中對應的定義符號的用法,在XSD中使用<notation>元素定義符號,用來標識XML文檔中的外部資料,該元素可接受的屬性有:
- id:指定該符號的唯一標識,通常無需指定
- name:指定該符號的名稱,是一個必填屬性,而且該名稱在整個XSD內必須是唯一的
- public:指定該符號所標識資料的外部格式或對應處理常式,必填屬性,相當於DTD中<!NOTATION>中PUBLIC的作用
- system:指定該符號所標識資料的外部格式或對應處理常式,可選屬性,相當於DTD中<!NOTATION>中SYSTEM的作用