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