新的 XML Schema 系統即將成為 W3C 推薦標准,目的是為了克服 DTD 的局限性(請參閱側欄, DTD 的局限性 ),為 XML 文檔提供豐富的語法結構。本文展示了模式的靈活性,說明如何使用 XML Schema 系統來定義最基本的 XML 文檔構造塊——元素。
XML Schema 比 DTD 更強大。為了說明 XML Schema 機制的強大功能,下面三個程序清單簡要比較了表示元素的不同方式。 清單 1給出了一個 XML 文檔片段, 清單 2用 DTD 語法聲明了這兩個元素, 清單 3則是相應的 XML Schema 語法形式。要注意, 清單 3中所用的是相同的 XML 語法。通過模式,驗證解析器可以檢查元素 InvoiceNo 是否是正整數,元素 ProductID 的首字符是否為 A 到 Z 之間的字母,後面為六個阿拉伯數字。相反,引用 DTD 的驗證解析器只能檢查這些元素是否用字符串表示。
清單 1:XML 文檔片段
<InvoiceNo>123456789</InvoiceNo>
<ProductID>J123456</ProductID>
清單 2:描述清單 1 中元素的 DTD 片段
<!ELEMENT InvoiceNo (#PCDATA)>
<!ELEMENT ProductID (#PCDATA)>
清單 3:描述清單 1 中元素的 XML Schema
<element name='InvoiceNo' type='positive-integer'/>
<element name='ProductID' type='ProductCode'/>
<simpleType name='ProductCode' base='string'>
<pattern value='[A-Z]{1}d{6}'/>
</simpleType>
在 XML Schema 中使用名稱空間
在這個協作的世界中,一個人可能處理來自多個其他團體的文檔,而不同的團體可能希望以不同的方式表示他們的數據元素。此外,他們還可能在一個文檔中引用不同團體創建的同名元素。如何區分相同名字的不同定義呢?XML Schema 使用名稱空間區分這些定義。
附:
DTD 的局限性
(盡管作為描述結構化信息的一種機制,DTD 成功地為 SGML 和 Html 開發人員服務了 20 年,但與 XML Schema 相比,它存在著嚴重的局限性。
DTD 要求元素由以下三種成分組成:
DTD 不使用 XML 語法,對類型和名稱空間僅提供有限的支持。)
一個給定的 XML Schema 定義了一組新名字,如元素名、類型名、屬性名、屬性組名,這些名字的定義和聲明都寫在模式中。 清單 3定義的名字包括 InvoiceNo 、 ProductID 和 ProductCode 。
我們說模式中定義的名字屬於它的 目標名稱空間。名稱空間本身有一個固定但沒有限制的名字,必須符合 URL 語法。比如,對於 清單 3中模式片段,您可以把名稱空間的名字設為: http://www.SampleStore.com/Account 。
名稱空間的名字語法容易讓人混淆,盡管以 http:// 開始,那個 URL 並不指向一個包含模式定義的文件。事實上,這個 URL http://www.SampleStore.com/Account 根本沒有指向任何文件,只是一個分配的名字。
模式中的定義和聲明可能引用屬於其他名稱空間的名字。在本文中,我們稱這些名稱空間為 源名稱空間。每個模式都有一個目標名稱空間,但可能有多個源名稱空間。名稱空間的名字可能相當長,但在 XML 文檔中通過 XMLns 聲明可使用簡寫形式。為了說明這些概念,我們可以向前述 清單 4中的示例模式中添加更多的內容。
清單 4:目標名稱空間和源名稱空間
<!--XML Schema fragment in file schema1.xsd-->
<xsd:schema targetNamespace='http://www.SampleStore.com/Account'
xmlns:xsd='http://www.w3.org/1999/XMLSchema'
XMLns:ACC= 'http://www.SampleStore.com/Account'>
<xsd:element name='InvoiceNo' type='xsd:positive-integer'/>
<xsd:element name='ProductID' type='ACC:ProductCode'/>
<xsd:simpleType name='ProductCode' base='xsd:string'>
<xsd:pattern value='[A-Z]{1}d{6}'/>
</xsd:simpleType>
在 清單 4的 XML Schema 中, targetNamespace 的名字是 http://www.SampleStore.com/Account ,其中包含的名字有 InvoiceNo 、 ProductID 和 ProductCode 。 schema 、 element 、 simpleType 、 pattern 、 string 和 positive-integer 這些名字屬於源名稱空間 http://www.w3.org/1999/XMLSchema ,通過 xmlns 聲明縮寫為 xsd 。別名 xsd 沒有任何特殊的地方,我們可以選擇任何其他的名字。在本文後面的部分為了方便和簡化起見,我們使用 xsd 代表名稱空間 http://www.w3.org/1999/XMLSchema ,在一些代碼片段中省略了限定符 xsd 。在這個例子中, targetNamespace 偶爾也作為一個源名稱空間,因為要使用名字 ProductCode 定義其他的名字。
圖 1:清單 4 中的名稱空間
清單 4中的模式片段不需要指定源模式文件的位置。對於整個“模式的模式”, http://www.w3.org/1999/XMLSchema ,不需要指定位置,因為它的位置是人所共知的。對於源名稱空間 http://www.SampleStore.com/Account ,也不需要指定位置,因為它恰好是該文件中定義的目標名稱空間。為了更好地理解如何指定模式的位置和使用默認名稱空間,看一看 清單 5中擴展的例子。
清單 5:多個源名稱空間,導入一個名稱空間
<!--XML Schema fragment in file schema1.xsd-->
<schema targetNamespace='http://www.SampleStore.com/Account'
xmlns='http://www.w3.org/1999/XMLSchema'
XMLns:ACC= 'http://www.SampleStore.com/Account'
XMLns:PART= 'http://www.PartnerStore.com/PartsCatalog'>
<import namespace='http://www.PartnerStore.com/PartsCatalog'
schemaLocation='http://www.ProductStandards.org/repository/alpha.xsd'/>
<element name='InvoiceNo' type='positive-integer'/>
<element name='ProductID' type='ACC:ProductCode'/>
<simpleType name='ProductCode' base='string'>
<pattern value='[A-Z]{1}d{6}'/>
</simpleType>
<element name='stickyGlue' type='PART:SuperGlueType'/>
清單 5中多了一個名稱空間引用: http://www.PartnerStore.com/PartsCatalog 。這個名稱空間不同於 targetNamespace 和標准名稱空間。因此必須使用 import 聲明元素引入,該元素的 schemaLocation 屬性指明包含模式的文件位置。默認的名稱空間是 http://www.w3.org/1999/XMLSchema ,它的 xmlns 聲明沒有名字。每個非限定的名字如 schema 和 element ,都屬於默認名稱空間 http://www.w3.org/1999/XMLSchema 。如果模式從一個名稱空間中引用了多個名字,將其指定為默認名字空間更方便。
一個 XML 實例文檔可能引用多個名稱空間的元素名,這些名稱空間定義在不同模式中。為了引用和簡化名稱空間的名字,同樣要使用 xmlns 聲明。我們使用 XML Schema 實例名稱空間的 schemaLocation 屬性指定文件的位置。要注意,該屬性不同於上一個例子中 xsd 名稱空間的同名屬性 schemaLocation 。
清單 6:使用來自多個模式的多個名稱空間的名字
<?XML version="1.0"?>
<ACC:rootElement XMLns:ACC='http://www.SampleStore.com/Account'
XMLns:PART='http://www.PartnerStore.com/PartsCatalog'
xmlns:xsi='http://www.w3.org/1999/XMLSchema-instance'
xsi:schemaLocation='http://www.PartnerStore.com/PartsCatalog
http://www.ProductStandards.org/repository/alpha.xsd
http://www.SampleStore.com/Account
http://www.SampleStore.com/repository/schema1.xsd'>
<ACC:InvoiceNo>123456789</ACC:InvoiceNo>
圖 2:清單 5 和清單 6 的名稱空間
定義元素
定義元素就是定義元素的名字和內容模型。在 XML Schema 中,元素的內容模型由其類型定義,因此 XML 文檔中實例元素的值必須符合模式中定義的類型。
類型包括簡單類型和復雜類型。簡單類型的值不能包含元素或屬性。復雜類型可以產生在其他元素中嵌套元素的效果,或者為元素增加屬性。(到目前為止本文中的例子都是用戶定義的簡單類型,比如 ProductCode )。XML Schema 規范也包括預定義的簡單類型(請參閱側欄 簡單類型)。 派生的簡單類型約束了基類型的值。比如,派生簡單類型 ProductCode 的值是基類型 string 值的子集。
簡單的、非嵌套的元素是簡單類型
不含屬性或其他元素的元素可以定義為簡單類型,無論是預定義的簡單類型還是用戶定義的簡單類型,如 string 、 integer 、 decimal 、 time 、 ProductCode 等等。
清單 7:一些元素的簡單類型
<element name='age' type='integer'/>
<element name='price' type='decimal'/>
帶有屬性的元素必須是復雜類型
現在,試著向 清單 7中的簡單元素 price 增加屬性 currency 。您不能這樣做,因為簡單類型的元素不能有屬性。如果希望增加屬性,您必須把 price 元素定義成復雜類型。在 清單 8的例子中,我們定義了一個 匿名類型,沒有明確地命名這個復雜類型。換句話說,沒有定義復雜類型 complexType 的 name 屬性。
清單 8:一個復雜元素類型
<element name='price'>
<complexType base='decimal' derivedBy='extension'>
<attribute name='currency' type='string'/>
</complexType>
</element>
<!-- In XML instance document, we can write: <price currency='US'>45.50</price> -->
嵌入其他元素的元素必須是復雜類型
在 XML 文檔中,一個元素可能嵌入其他的元素。這種要求可以在 DTD 中直接表示。但 XML Schema 定義一個元素,這個元素有一個類型,而這個類型可以包含其他元素和屬性的聲明。 表 1給出了一個簡單的例子。
表 1:DTD 和 XML Schema 中復雜數據類型的比較
XML 文檔
<Book>
<Title>Cool XML<Title>
<Author>Cool Guy</Author>
</Book>
DTD
<Book>
<Title>Cool XML<Title>
<Author>Cool Guy</Author>
</Book>
XML Schema
<Book>
<Title>Cool XML<Title>
<Author>Cool Guy</Author>
</Book>
<!ELEMENT Book (Title, Author)>
<!ELEMENT Title (#PCDATA)>
<!ELEMENT Author (#PCDATA)>
<element name='Book' type='BookType'/>
<complexType name='BookType'>
<element name='Title' type='string'/>
<element name='Author' type='string'/>
</complexType>
盡管 表 1中的 XML 代碼同時滿足 DTD 與 XML Schema 片段,但兩者之間有一個很大的區別。在 DTD 中所有的元素都是全局性的,而表中的 XML Schema 允許把 Title 和 Author 定義成局部的——只出現在元素 Book 中。為了在 XML Schema 中實現與 DTD 聲明完全相同的效果,元素 Title 和 Author 必須是全局范圍的,如 清單 9中所示。元素 element 的 ref 屬性使您能夠引用前面聲明的元素。
清單 9:用全局簡單類型定義的復雜類型
<element name='Title' type='string'/>
<element name='Author' type='string'/>
<element name='Book' type='BookType'/>
<complexType name='BookType'>
<element ref='Title'/>
<element ref='Author'/>
</complexType>
在 表 1和 清單 9所示的例子中, BookType 是全局性的,可用於聲明其他元素。相反, 清單 10將該類型局部地定義到元素 Book 中,而且定義成匿名元素。要注意, 表 1中的 XML 文檔片段與表 1、 清單 9和 清單 10中三個模式片段都匹配。
清單 10:隱藏 BookType 作為本地類型
<element name='Title' type='string'/>
<element name='Author' type='string'/>
<element name='Book'>
<complexType>
<element ref='Title'/>
<element ref='Author'/>
</complexType>
</element>
表示元素的復雜約束
對於表示元素內容模型的約束,XML Schema 比 DTD 提供了更大的靈活性。在最簡單的層次上,像在 DTD 中那樣,您可以把屬性和元素聲明關聯起來,指明能夠出現的給定元素集合序列:只能出現 1 次(1)、出現 0 次或多次(*)或者出現 1 次或多次(+)。您還可以表示 XML Schema 中的其他約束,比方說使用 element 元素的 minOccurs 和 maxOccurs 屬性,以及 choice 、 group 和 all 元素。
清單 11:表示元素類型的約束
<element name='Title' type='string'/>
<element name='Author' type='string'/>
<element name='Book'>
<complexType>
<element ref='Title' minOccurs='0'/>
<element ref='Author' maxOccurs='2'/>
</complexType>
</element>
在 清單 11中, Book 中 Title 的出現是可選的(類似 DTD 的 '?')。但是, 清單 11也說明 Book 元素中至少要有一個但不能超過兩個作者。 element 的 minOccurs 和 maxOccurs 屬性的默認值是 1。元素 choice 只允許它的一個子女出現在實例中。另外一個元素 all ,表示這樣的約束:組中的所有子元素可以同時出現一次,或者都不出現,它們可以按任意的順序出現。 清單 12表示 Title 和 Author 兩者必須同時出現(順序任意)在 Book 中,或者都不出現。這種約束很難在 DTD 中表示。
清單 12:指出必須為元素定義所有的類型
<xsd:element name='Title' type='string'/>
<xsd:element name='Author' type='string'/>
<xsd:element name='Book'>
<xsd:complexType>
<xsd:all>
<xsd:element ref='Tile'/>
<xsd:element ref='Author'/>
</xsd:all>
</xsd:complexType>
</xsd:element>
更上層樓
我們已經討論了在 XML Schema 中定義元素所需的最基本的概念,通過一些簡單的例子使您領略到它的強大功能。還有一些更強大的機制:
可以通過 W3C 站點(請參閱 參考資料)的文檔進一步研究 XML Schema,或者訪問 dW XML 專區了解更多的內容。目前,XML Schema 規范已經被批准,並成為候選推薦標准(Candidate Recommendation),毫無疑問您將越來越多地用到它。