2006
年
8
月
23
日
星期三
XSD 淺學筆記
簡單明快的 XSD 的入門筆記,希望能讓你和我一樣,用半天時間步入第一道門檻。
這一片記錄基礎知識,第二篇會是些進階知識和總結,然后你就可以寫出自己的第一個 XSD 文檔,并用來驗證一個 XML 文檔了。
XSD 是什么 ?
一個 xml schema 是用來描述 xml 文檔結構的,而 XSD 是 xml schema definition , 是繼 DTD 后的基于 xml 的 schema 語言,比起 DTD ,它有更好的擴展性,增加了功能,更重要的是,它本身就是以 xml 來寫的,而不需要象 DTD 那樣重新學一門語言。同時也可以利用所有對 xml 有效的便利。
那么為什么要有 schema 呢, xml 的 well-formed 是不足夠的,一個語法上合法的 xml 仍然可能有錯誤,而這些錯誤可能導致嚴重的應用后果。
基礎概念
第一印象
??????
以下是一份 xml 文檔
<?xml version="1.0"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
而它對應的一份 xsd 會是這樣的:
<?xml version="1.0"?>
<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="note">
??? <xs:complexType>
????? <xs:sequence>
?????? <xs:element name="to" type="xs:string"/>
?????? <xs:element name="from" type="xs:string"/>
?????? <xs:element name="heading" type="xs:string"/>
?????? <xs:element name="body" type="xs:string"/>
????? </xs:sequence>
??? </xs:complexType>
</xs:element>
</xs:schema>
簡單元素:
簡單元素是不包含其他元素和屬性的元素。
定義簡單元素的語法為:
<xs:element name="xxx" type="yyy"/>
常用的內(nèi)建類型有:
xs:string
xs:decimal
xs:integer
xs:boolean
xs:date
xs:time
可以通過 default 屬性和 fixed 屬性來修飾。
<xs:element name="color" type="xs:string" default="red"/>
<xs:element name="color" type="xs:string" fixed="red"/>
屬性:
只有復合元素可以有屬性,但屬性本身總是被定義為簡單類型的。
<xs:attribute name="xxx" type="yyy"/>
除了和簡單元素的定義一樣可以用 default 和 fixed 來作為屬性之外,還可以用 use 屬性,如果把 use 屬性指定為“ required ”,就說明這個屬性在 xml 文檔中是必須指明的,默認情況下屬性的使用是可選的。
限制
當一個元素或者屬性定義了類型( type ), 就可以用 restriction 來限制這個類型, restriction 又叫 facet ,可以為類型增添更多的細節(jié)要求。當 xml 文檔中對應的元素值違反了這個 restriction 就不能通過檢驗。限制是 XSD 里比較常用的內(nèi)容,我們會看大量的例子。
對數(shù)值大小的限制:(只能取 0 到 120 的閉區(qū)間)
<xs:element name="age">
<xs:simpleType>
? <xs:restriction base="xs:integer">
??? <xs:minInclusive value="0"/>
??? <xs:maxInclusive value="120"/>
? </xs:restriction>
</xs:simpleType>
</xs:element>
將值限制在一組既定值內(nèi):(類似于枚舉 enumeration )
<xs:element name="car">
<xs:simpleType>
? <xs:restriction base="xs:string">
??? <xs:enumeration value="Audi"/>
??? <xs:enumeration value="Golf"/>
??? <xs:enumeration value="BMW"/>
? </xs:restriction>
</xs:simpleType>
</xs:element>
限制一定范圍的值:(只能取小寫的 26 個字母)
<xs:element name="letter">
<xs:simpleType>
? <xs:restriction base="xs:string">
??? <xs:pattern value="[a-z]"/>
? </xs:restriction>
</xs:simpleType>
</xs:element>
(只能取長度為 3 的大寫字母組合)
<xs:element name="initials">
<xs:simpleType>
? <xs:restriction base="xs:string">
??? <xs:pattern value="[A-Z][A-Z][A-Z]"/>
? </xs:restriction>
</xs:simpleType>
</xs:element>
(只能取長度為 3 的字母,大小寫均可)
<xs:element name="initials">
<xs:simpleType>
? <xs:restriction base="xs:string">
??? <xs:pattern value="[a-zA-Z][a-zA-Z][a-zA-Z]"/>
? </xs:restriction>
</xs:simpleType>
</xs:element>
(只能取 xyz 中的一個)
<xs:element name="choice">
<xs:simpleType>
? <xs:restriction base="xs:string">
??? <xs:pattern value="[xyz]"/>
? </xs:restriction>
</xs:simpleType>
</xs:element>
(只能取長度為 5 的數(shù)字串)
<xs:element name="prodid">
<xs:simpleType>
? <xs:restriction base="xs:integer">
??? <xs:pattern value="[0-9][0-9][0-9][0-9][0-9]"/>
? </xs:restriction>
</xs:simpleType>
</xs:element>
(只能取任意長度的小寫字符串,長度可以為 0 )
<xs:element name="letter">
<xs:simpleType>
? <xs:restriction base="xs:string">
??? <xs:pattern value="([a-z])*"/>
? </xs:restriction>
</xs:simpleType>
</xs:element>
(有了上一個,你自然也會猜到這一個:只能取長度大于 0 的字符串)
<xs:element name="letter">
<xs:simpleType>
? <xs:restriction base="xs:string">
??? <xs:pattern value="([a-z][A-Z])+"/>
? </xs:restriction>
</xs:simpleType>
</xs:element>
(選取,其實和前面的枚舉式功效類似,只能取其一)
<xs:element name="gender">
<xs:simpleType>
? <xs:restriction base="xs:string">
??? <xs:pattern value="male|female"/>
? </xs:restriction>
</xs:simpleType>
</xs:element>
(特定長度的字符數(shù)字串,用作密碼最合適。)
<xs:element name="password">
<xs:simpleType>
? <xs:restriction base="xs:string">
??? <xs:pattern value="[a-zA-Z0-9]{8}"/>
? </xs:restriction>
</xs:simpleType>
</xs:element>
(如果不需要在 base 上加內(nèi)容限制,也可以這樣來表達長度)
<xs:element name="password">
<xs:simpleType>
? <xs:restriction base="xs:string">
??? <xs:length value="8"/>
? </xs:restriction>
</xs:simpleType>
</xs:element>
(設定長度區(qū)間)
<xs:element name="password">
<xs:simpleType>
? <xs:restriction base="xs:string">
??? <xs:minLength value="5"/>
??? <xs:maxLength value="8"/>
? </xs:restriction>
</xs:simpleType>
</xs:element>
另外,在 xml 里,空白符的情況比較特別,不小心處理就得不到你要的真正效果。
(保留所有的空白符)
<xs:element name="address">
<xs:simpleType>
? <xs:restriction base="xs:string">
??? <xs:whiteSpace value="preserve"/>
? </xs:restriction>
</xs:simpleType>
</xs:element>
( 所有的回車,過行,制表符,長空白都被替換成相應長度的空格符 )
<xs:element name="address">
<xs:simpleType>
? <xs:restriction base="xs:string">
??? <xs:whiteSpace value="replace"/>
? </xs:restriction>
</xs:simpleType>
</xs:element>
(所有空白符都被變?yōu)閱慰崭穹孜部瞻锥急蝗サ簦?/span>
<xs:element name="address">
<xs:simpleType>
? <xs:restriction base="xs:string">
??? <xs:whiteSpace value="collapse"/>
? </xs:restriction>
</xs:simpleType>
</xs:element>
最后,上面說到的所有的限制,還可以以下面這種格式來寫,把 simpleType 加上名字,在元素中的 type 引用這個名字,好處就是它不再單獨屬于這個元素或者屬性的定義了,其他元素可以復用這個類型限制,類似于面向對象編程語言中的包裝與復用。
<xs:element name="car" type="carType"/>
<xs:simpleType name="carType">
? <xs:restriction base="xs:string">
??? <xs:enumeration value="Audi"/>
??? <xs:enumeration value="Golf"/>
??? <xs:enumeration value="BMW"/>
? </xs:restriction>
</xs:simpleType>
復合元素
復合元素的定義就和簡單元素的剛好相反了,就是包含其他元素或屬性的元素。
細分一下有四種:
空元素;
<product pid="1345"/>
只包含其他元素的;
<employee>
<firstname>John</firstname>
<lastname>Smith</lastname>
</employee>
只有文本內(nèi)容的;
<food type="dessert">Ice cream</food>
同時包括文本內(nèi)容和其他元素的。
<description>
It happened on <date lang="norwegian">03.03.99</date> ....
</description>
而這四個同時又都可以有屬性。
接下來我們一一詳細介紹。
<product prodid="1345" />
空元素的定義語法:
<xs:element name="product">
? <xs:complexType>
??? <xs:attribute name="prodid" type="xs:positiveInteger"/>
? </xs:complexType>
</xs:element>
<person>
<firstname>John</firstname>
<lastname>Smith</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:sequence>
? </xs:complexType>
</xs:element>
用 xs:sequence 來定義這些元素必須按照這個次序出現(xiàn),類似于 sequence 這樣的指示符還有幾個,稍后統(tǒng)一介紹。
定義一個只有文本內(nèi)容和屬性的復合元素,我們需要用一個 simpleContent 標記,再用一個 restriction 或者 extension 來限制文本的內(nèi)容 :
<xs:element name="somename">
? <xs:complexType>
??? <xs:simpleContent>
????? <xs:extension base="basetype">
??????? ....
??????? ....
????? </xs:extension>????
??? </xs:simpleContent>
? </xs:complexType>
</xs:element>
或:
<xs:element name="somename">
? <xs:complexType>
??? <xs:simpleContent>
????? <xs:restriction base="basetype">
??????? ....
??????? ....
????? </xs:restriction>????
??? </xs:simpleContent>
? </xs:complexType>
</xs:element>
例子:
<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>
注意 extension 的 integer 是限制 shoesize 的文本內(nèi)容,而 attribute 的 string 是限制 attribute 本身的內(nèi)容的。
對應這個復合模式的 xml 可以是:
<shoesize country="
要描述混合的復合元素:
<letter>
Dear Mr.<name>John Smith</name>.
Your order <orderid>1032</orderid>
will be shipped on <shipdate>
</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>
只是在包含其他元素的同時指定 mixed 等于“ true “,而 sequence 或其他指示符的使用依然有效。你的文本可以穿插于元素之間,但元素的出現(xiàn)次序仍受 sequence 的限制。
記得簡單元素里的復用嗎,這里同樣可以,在 complexType 標記里加上 name 屬性,就完成了分離和復用了,對上面所有的復合類型都是通用的。即使寫 xsd ,也要象 oop 語言那樣,通過復用來提高修改的效率,同時讓頁面看起來整潔清晰,至少,我是有著這樣的偏執(zhí)的,呵呵。
指示符里有以下幾種:
順序指示符:
All 所有元素可以不分順序出現(xiàn),但只能出現(xiàn)一次。
Choice 只有其中一個可以出現(xiàn)
Sequence 前面說過了,必須按順序出現(xiàn)。
上面的限制可以配合次數(shù)指示符加以進一步的限制:
maxOccurs 最多出現(xiàn)次數(shù)
minOccurs 最少出現(xiàn)次數(shù)
例如:
<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>
注意用了 all 的時候,最大次數(shù)還是不能超過 1 ,最小可以是 0 或 1 。
組指示符:
Group 元素組
attributeGroup 屬性組
通過例子來看看:
<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 必須包含已經(jīng)用順序指示符包含起來的元素。
定義后,別的地方可以用 ref 來引用:
<xs:complexType name="personinfo">
? <xs:sequence>
??? <xs:group ref="persongroup"/>
??? <xs:element name="country" type="xs:string"/>
? </xs:sequence>
</xs:complexType>
以下這兩個是對應的 attribute group 的用法:
<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:element name="person">
? <xs:complexType>
??? <xs:attributeGroup ref="personattrgroup"/>
? </xs:complexType>
</xs:element>
這一篇到這里為止。
?