XML Schema是2001年5月正式發布的W3C的推薦標準,經過數年的大范圍討論和開發如今終究塵埃落定,成為全球公認的XML環境下首選的數據建模工具。
使用DTD雖然帶來較大的方便,但是,DTD存在1些缺點:1是它用不同于XML的語言編寫,需要不同的分析器技術。這增加了工具開發商的負擔,下降了軟件瘦身的可能性,另外開發人員需要多學1門語言及其語法。而XML Schema是按標準XML規則編寫的,更容易掌握。2是DTD不支持名稱空間。隨著大部份的數據處理日趨以XML為中心,信息的相互聯系變得日趨普及與深入,名稱空間作用也將凸現。3是DTD在支持繼承和子類方面的局限性。由于面向對象技術的出現,對繼承和子類的支持已成為軟件技術領域的主流概念。最后,DTD沒有數據類型的概念,沒法對特定元素施加數據類型,對強迫性結構化無計可施,例如,如何規定名為Date的數據必須包括有效值。
這些就要依托XML Schema了。XML Schema不但可以定義XML文檔的結構而且還允許束縛文檔的內容,這不同于DTD。另外,1個 XML Schema本身就是1個XML文檔,其基于標簽的語法比DTD中的特殊字符要清楚多了。XML Schema正是針對這些DTD的缺點而設計的,它完全使用XML作為描寫手段,具有很強的描寫能力、擴大能力和處理保護能力。
XML Schema是用1套預先規定的XML元素和屬性創建的,這些元素和屬性定義了文檔的結構和內容模式。
XML Schema也是Web Services技術中需要使用的1個基本工具,但是其實不是XML Schema的所有特性都會被廣泛地使用,因此,本書將不對XML Schema規范做系統的介紹。目前主要有兩種重要的模式:Microsoft XML Schema和W3C XML Schema,本章主要討論W3C XML Schema。
在下面的例子中,通過使用出現在Schema元素中的名稱空間聲明xmlns:xsd= “http://www.w3.org/2001/XMLSchema”,使得模式文檔中的每個元素都有1個與XML Schema名稱空間相干聯的名稱空間前綴xsd。雖然在語法上,可使用任意的前綴情勢,但是,名稱空間前綴xsd被約定用于表示XML Schema名稱空間。由于使用一樣的前綴,所以一樣的關聯就會出現在內置的簡單類型的名字中,例如xsd:string。這類情勢關聯的目的是用來表示當前的元素或簡單類型屬于XML Schema語言的內置定義,而不屬于模式文檔作者自己的辭匯表。為了在這里清楚并且簡單地表示,僅提及元素的名字和簡單類型名,而疏忽它們的前綴xsd。
1個XSDL(XML Schema Definition Language)文檔由元素、屬性、名稱空間和XML文檔中的其他結點構成,并且最少要包括:schema根元素、XML模式名稱空間的定義和元素定義。
【例5.1】 關于書籍信息的XML文檔,代碼如源程序code5_1.xml所示。
如何寫這個XML文檔的Schema呢?可以簡單地依照它的結構來定義它的每一個元素。首先加入1個xsd:schema元素。
每一個Schema文檔都是從schema元素開始,并且只能有1個,用以控制Schema所使用的名稱空間和另外幾個選項,現在的Schema標準有好幾種,這里決定它所采取的標準,因此是非常重要的。
對應著XML文檔的book元素,一樣也定義1個名為book的元素(element)。由于這個元素有屬性(attributes)和非文本的子元素(non-text children),所以認為它是1個復雜類型(complexType)。而對簡單類型,只能有值,不能有子元素或屬性。同時還注意到book元素下的子元素,都依照1定的順序排列,因此使用順序元素(sequence element)來描寫。
順序元素(sequence element)是1個定義子元素排列順序的元素,在下面的章節,還將介紹其他類似的元素,如選擇(choice)和全選(all)。
接著定義title和author,都是xsd:string類型的簡單元素,由于沒有屬性(attributes)或子元素。xsd:string是1個已在名域中預定義了的XML Schema類型中的1個。
接著,來處理publish元素,它也是1個復雜類型,注意它的基數的定義。
同其他Schema定義語言不1樣,W3C XML Schema允許定義1個元素的使用基數,能指定元素的minOccurs(最小數)和maxOccurs(最大數)。這里設置maxOccurs為unbounded,這意味著能有任意多的publish元素。這兩個屬性的默許值都是1。下面,用一樣的方法定義其他的子元素。
下面封閉complexType和element等元素。
這樣publish元素就完成了,然后封閉book的sequence元素。
現在,聲明book元素的屬性,通常是在最后這么做。這樣做沒有甚么特別的緣由,只不過W3C XML Schema工作組認為在元素后定義屬性感覺更加自然。
最后,封閉所有剩下的元素。
至此,1個Schema已完成了。其中,最關鍵的在于根據文檔的上下關系來定義每個元素和屬性,并且允許有多個同名元素帶有不同的內容。為了這個目的,W3C XML Schema被設計成1種有作用域的語言,它的每個定義只能被它定義的子元素所看見。
【例5.2】 關于books.xml模式定義的完全例子,代碼如源程序code5_2.xsd所示。
符合某個模式的文檔稱為實例。實例可以根據特定的模式進行驗證。需要聲明XML文檔的Schema實例名稱空間(xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”),并把名稱空間映照到前綴xsi。實例與模式之間有多對多的關系。1個模式可以描寫多個有效的實例(通過使用不同的根元素類型來實現),一樣,1個實例也能夠被多個模式描寫。例如1個實例可能具有多個模式,它們有不同的驗證級別。其中1個模式可能只驗證結構,而另外一個模式則根據數據類型來檢查每個數據項。
1. Schema的作用
Schema文檔用來驗證XML文檔的正確性,用來判斷實例是不是符合模式中所描寫的所有束縛,觸及到檢查實例中所有的元素和屬性。
Schema主要檢驗以下內容:
(1) 驗證數據的顯示格式是不是正確及是不是超越值的范圍;
(2) 驗證所有必須的信息都存在;
(3) 確保不同使用者對文檔理解的方式相同。
除對XML文檔的驗證外,Schema文檔還在1定程度上擴充實例:
(1) 為元素和屬性添加默許值和固定值;
(2) 使具有簡單類型的元素和屬性值中的空白符規范化。
2. Schema的援用
1個模式可能由多個模式文檔構成。多個模式文檔通過包括或導入機制來構成模式,當其他模式文檔與主模式文檔具有相同的目標名稱空間時,需要使用包括;當模式文檔之間各自具有不同的目標名稱空間時,需要使用導入。下面的例子建立1個單獨用來驗證實例的模式文檔。
【例5.3】 關于多個模式文檔通過包括實現定義的例子,代碼如源程序code5_3.xsd所示。
要驗證XML文檔,必須指定Schema文檔的位置。模式的位置可以利用帶著名稱空間模式的xsi:schemaLocation屬性和不帶名稱空間XML模式的xsi:noNamespace SchemaLocation 屬性來指定,它們位于根/頂級元素中或XML文檔的任何其他元素中。
當Schema文檔不包括targetNamespace屬性時,應當通過XML文檔根元素的noNamespace SchemaLocation屬性及W3C的Schema實例名稱空間(xmlns:xsi=“http://www.w3.org /2001/XML Scheam-instance”)來援用XML Schema文件。針對上面的實例修改以下:
但是,如果Schema文檔包括了1個targetNamespace 屬性,在XML文檔中就將通過schemaLocation屬性而不是noNamespaceSchemaLocation屬性來援用Schema文檔。而且,這個屬性所指定的值必須是完全的。它需要包括以空格分開的兩部份,前1部份是URI,這個URI與Schema文檔的targetNamespace屬性內部援用的URI是1致的;后1部份是Schema文件的完全路徑及名稱。另外,XML文檔的根元素也必須聲明Schema實例名稱空間(xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”)。Schema文檔以下所示:
則修改上面的實例為
元素是創建XML文檔的主要構建材料。在W3C XML Schema中,元素通過使用element元素實現。元素聲明用于給元素指定元素類型名稱、內容和數據類型等屬性。在XSDL中,元素聲明可以是全局的,也能夠是局部的。
在schema文檔中必須定義1個且只能定義1個schema根元素。根元素不但表明了文檔類型,而且還包括模式的束縛、XML模式名稱空間的定義,其他名稱空間的定義、版本信息、語言信息和其他1些屬性。定義以下:
其中name屬性指定Schema名稱,也能夠不需要。xmlns指定所屬名稱空間,緊跟在后面的xsd則是該名稱空間的名稱,名稱空間http://www.w3.org/2001/XMLSchema被映照到xsd前綴,在后面將詳細說明名稱空間。
XSD中的元素是利用element來聲明的。其中name屬性是元素的名字,type屬性是元素值的類型,在這里可以是XML Schema中內置的數據類型或其他類型。具體定義格式以下:
name是元素類型的名稱,必須是以字母或下劃線開頭,而且只能夠包括字母、數字、下劃線、連接符及句號。type屬性是必要的,說明元素的數據類型。
下面的例子定義全局元素聲明author,為簡單字符串類型。
與以上文檔對應的有效XML文檔以下:
在元素的定義中還有兩個屬性:minOccurs和maxOccurs。其中minOccurs定義了該元素在父元素中出現的最少次數(默許為1,值為大于等于0的整數),maxOccurs定義了該元素在父元素中出現的最屢次數(默許為1,值為大于等于0的整數)。在maxOccurs中可以把值設置為unbounded,表示對元素出現的最屢次數沒有限制。
表示元素author的類型為string,出現的次數最少為0(就是可選),最多不限制。
1般來講,如果元素聲明出現在Schema文檔的頂級結構中,也就是說,它的父元素是schema,那末這些元素為全局元素。
相反,局部元素聲明只出現在復雜類型定義的內部,局部元素聲明只在該類型定義中使用,而不被其他復雜類型援用或在替換組中使用。不同的復雜類型,可以有相同元素類型名稱的局部元素。
【例5.4】 顯示title、author和price3種局部元素聲明的模式文檔,代碼如源程序code5_4.xsd所示。
默許值和固定值通過給空元素增加值的方式來擴大實例。如果文檔中存在空的元素,模式處理器根據模式文檔的定義,會插入默許值或固定值。在XSDL中,默許值和固定值分別通過default和fixed屬性設置。兩個屬性只能出現其中之1,由于它們是互斥的。
如果元素為空,就填入默許值。下例中,聲明了city元素,并指定了默許值為“佚名”。
必須注意的是,元素聲明中“空”的定義根據數據類型不同而有所不同。某些數據類型允許空值,包括string等。任何允許空字符串值的類型,元素都不會認為是空的,從而對字符串類型元素,默許值不會被填充。相反,integer數據類型的空元素通常會被認為是空的,從而將填入默許值。另外,如果元素的xsi:nil屬性被設置為true,那末就不會插入它的默許值。
元素的默許值行動見表5⑴。
固定值與默許值在相同的情況下添加,它們的差別僅在于如果元素具有1個值,則該值必須和固定值相等。當模式解析器肯定元素值和固定值實際上是不是相等時,會斟酌到元素的數據類型。price元素的數據類型為integer,所以整數1的所有情勢在實例中都會被接受,包括01、+1和周圍包括空白符的1。相反,對author元素具有數據類型為string,字符串“01”是無效的,由于與字符串“1”其實不相等。
依照以上定義,元素的固定值行動見表5⑵。
援用是利用element元素的ref屬性實現的。主要適用于避免在文檔中屢次定義同1個元素,應當將常常使用的元素定義為根元素的子元素,即為全局元素,這樣方便在文檔的任何地方援用它。如每本書籍都有作者,其他產品也會有作者,因此可以把author屬性聲明為全局元素,供文檔中多處援用。
【例5.5】 援用元素定義的模式文檔,代碼如源程序code5_5.xsd所示。
在這里還可以為某個定義的元素起1個別名,主要是利用element元素中的substitutionGroup屬性實現的。
方法以下:
以上文檔對應的有效XML文檔以下:
或:
屬性聲明用于命名屬性并使之與某個特定的簡單類型相干聯。在XSDL中,實現的方法是使用attribute元素。在XML Schema文檔中可以依照定義元素的方法定義屬性,但受限制的程度較高。它們只能是簡單類型,只能包括文本,且沒有子屬性。屬性是沒有順序的,而元素是有順序的。
使用屬性10分簡練,元素的功能比屬性強大,但在某些場合屬性是非常有用的。通常,對元數據使用屬性,而對數據則使用元素。如用屬性描寫單位、語言或元素值的時間相依性。
定義屬性的方法以下:
該語句定義了1個名為isbn的屬性,它的值必須是1個字符類型。
屬性也分全局和局部屬性。全局聲明的屬性是schema元素的子元素,在模式文檔中必須是唯1的。復雜類型的元素,使用ref屬性通過名稱來援用屬性。局部屬性聲明只出現在復雜類型定義中,它們僅能在類型定義中使用,而不能被其他類型重用。下面的例子顯示了兩個屬性——isbn和amount 的全局聲明,然后定義了1個復雜類型,使用ref屬性通過名稱來援用這兩個屬性。
use屬性用于唆使屬性是必須的還是可選的,它出現在屬性援用而不是屬性聲明中,由于它關系到屬性在復雜類型中的出現,而不是屬性本身。上面的例子定義的是全局的屬性定義方式,如果要在復雜類型里聲明屬性,可以參照下面的例子:
上面的例子描寫了isbn和amount兩個屬性的局部聲明,它們完全出現在復雜類型的定義中。局部聲明的屬性名稱,作用范圍僅限于復雜類型內,在同1個復雜類型定義中,兩個屬性使用相同的限定名稱是非法的。只有當屬性會被多個名稱空間的多個元素聲明使用到時,才提倡將該屬性聲明為全局屬性。
所有的屬性聲明都把屬性指定為某種簡單類型。所有的屬性都具有簡單類型而不是復雜類型,由于它們本身不能有子元素和屬性。
屬性聲明有3種方式:
(1) 在屬性聲明中通過用type屬性指定命名簡單類型。它可以是內置類型,也能夠是用戶自定義類型。
(2) 通過指定simpleType子屬性來指定匿名類型。
(3) 既沒有type屬性,又沒有simpleType子屬性,從而不指定特定類型。在這類情況下,屬性的類型為anySimpleType,它可以具有任何值,只有它是結構公道的XML文檔。
下例顯示4個屬性的聲明,采取了不同的類型指定方法。定義了grade屬性并賦予gradeType類型,amount屬性指定了內置類型integer,同時使用內嵌的匿名簡單類型來聲明bookcategory屬性,anything屬性沒有指定特定的類型。
對屬性來講,也能夠通過默許值和固定值的方式增加未出現的屬性來擴充實例。定義和擴充的方式與元素1致。在XSDL中,默許值和固定值分別通過default和fixed屬性設置。兩個屬性只能出現其中之1,由于它們是互斥的。
如果屬性在元素中默許,它的默許值將會被填入。如果屬性出現,且包括任意值,它將保持該值不變。下面的例子顯示了book元素的聲明,它包括1個amount屬性,該屬性被指定了默許值。
固定值與默許值在基本1樣的情況下被插入,區分在于,其值應和固定值相等。同時也會斟酌屬性的類型。
W3C XML Schema可以把XML文檔中的元素聲明為特定的類型,準予解析器檢查文檔的內容及其結構。XML Schema定義了兩種主要的數據類型:預定義簡單類型和復雜類型。這兩種數據類型之間的主要區分是復雜類型可以像數據1樣包括其他元素而簡單類型則只能包括數據。簡單類型給予了XML Schema低級類型檢查能力。
元素和屬性聲明都可使用簡單類型來描寫數據類型。
1. 簡單類型的種類
原子類型(不可分割的類型,如string、integer等系統內建的類型)、列表類型、聯合類型合起來統1稱為簡單類型。XML Schema具有低級類型檢查能力,允許把元素定義為表5⑶中的任何類型之1。賦予簡單類型的元素具有字符類型內容,但沒有子元素或屬性。
(1) 原子類型具有不可分割的值,如10和large。
(2) 列表類型的值為用空格符隔開的原子值列表,如10 large 2
(3) 聯合類型的值可以是原子值,也能夠是列表值。它們的區分在于該類型的有效值集是兩個或多個其他簡單類型值空間的聯合。如要對學生的成績評定等級,可以定義1個聯合類型,它允許的值既可以是0~100的整數,也能夠是優、良、合格或不合格。
在前面1些例子中,有幾個元素和屬性被聲明為簡單類型。其中1些簡單類型如 string 和integer是XML Schema中內置的類型,其他的1些則是源于(如果使用對象技術的語言就是繼承)內置的類型。
除此以外,新的簡單類型可以通過從現有的簡單類型(內置的簡單類型和源于內置簡單類型的簡單類型)引出定義。通常,通太重新束縛1個現有的簡單類型來引出1個新的簡單類型。換句話說,新類型的合法值范圍是現有類型的值范圍的子集。使用simpleType元夙來定義和命名新的簡單類型,使用restriction元夙來指出現有的基類型,并且用它來標識束縛值范圍的細節。
假定希望建立1個新的整數類型稱為myInteger,它的值范圍為10000~99999。那末定義應當基于簡單類型integer,然后定義它的值范圍為10000~99999。為了定義myInteger,這樣來束縛integer的范圍,示例以下:
這個例子顯示了由1個基本類型定義和兩個值域區間方面描寫的組合,通過這3個要素對myInteger實行定義。
2. 簡單類型的命名定義
簡單類型既可以為命名簡單類型又可以為匿名簡單類型。命名簡單類型總是在全局定義的,而且要求在模式的數據類型中具有唯1名稱。類型的名稱必須為XML無冒號名稱,即必須以字母或下劃線開始,只能包括字、數字母、下劃線、連字符和句點。如上面的例子,簡單類型名為myInteger。
這類類型的模式構造非常直接了當,但有些不實用。特別是如果定義了許多只利用1次而且包括非常少束縛的類型,在這類情況下,1個類型應當能夠被更簡單的定義。這樣的簡單定義通常的情勢是1個省略了名稱和外部援用開消的匿名類型。
在下面的示例中,publish元素聲明使用了匿名類型定義。1般來講,通過元素中是不是包括“type=”這個屬性可以判斷匿名屬性定義(或是匿名元素定義)。如果出現無名稱的類型定義,也能夠認為是匿名屬性(元素)定義。
簡單類型定義時,都是通過restriction元夙來定義限制,通過base屬性來規定1種基類型。在restriction內,可以任何順序指定任何面(facet),來對類型取值進1步限制。根據面的不同,這個元素或屬性具有不同的有效值。XML Schema面的定義見表5⑷。
對每一個內置的原子類型來講,都有1套定義時可用的面。如果某個面適用于某種原子類型,那末也適用于由該類型派生的簡單類型。這里有必要舉例說明枚舉的簡單類型定義,下面的例子定義了1個簡單類型category,用于說明書籍的種別。
1些用于描寫的參數能夠被利用到列表類型的定義中,它們是length、minLength、maxLength和enumeration。舉例來講,如果想定義1個列表類型,這個列表類型正好包括了6個分類項名。首先從category類型定義1個新的列表類型,稱為cateList,然后通過限制cateList導出只有3個項的threeBookCate類型。具體的定義以下:
類型為threeBookCate的元素必須有3個項,它們中的每個項必須是1個枚舉類型category的原子類型(枚舉類型將在后面的章節中介紹),在示例后半部份的實例文檔中就是1個具體的利用例子。
需要注意的是,從原子類型string可以導出1個列表類型,但是,在1個string中或許會帶有空格,而空格在1個列表類型實例中是作為分隔符使用的,因此當在使用基類型為string的列表類型時,應當格外謹慎。舉例來講,假定定義了1個length取值為3的列表類型,同時這個列表類型基于類型string。下面由3個元素這樣組成的列表是合法的Asia Europe Africa;而由3個元素這樣組成的列表是不合法的Asia Europe Latin America。即便Latin America在列表外可以作為單獨的1個字符串存在,但當它包括在列表中時,在Latin和America之間的空格使得第4個項被有效地生成了,因爾后面的例子不符合只有3個項的列表類型定義。
5. 聯合類型
利用原子類型和列表類型,1個元素或屬性的值可以為1個或多個原子類型(列表類型)的實例。與之相比較,1個聯合類型(Union Type)包括了多個原子類型或列表類型,而利用了聯合類型的元素或屬性,它們的值可以是聯合類型中所包括的這些原子類型或列表類型中的任何1個類型實例。為了說明這1點,建立1個用于表示學生成績的由評定等級或數字列表的聯合類型。gradeUnion聯合類型由1個原子類型和1個列表類型構成。
上一篇 HTTP詳解
下一篇 android應用版本更新策略