理解XML Schema: XML Schema進階(I))

來源:互聯網
上載者:User
本文章系列將結合執行個體對XML Schema,這個目前國際標準的XML建模工具進行入門層級的概述,希望大家通過本系列的學習能夠初步掌握XML Schema的使用方法和XML Schema文檔執行個體的具體語義。本文主要針對XML Schema中的命名空間的使用做了介紹,圍繞命名空間的使用,闡述了模式的範圍以及命名空間對元素/屬性的限定能力。在命名空間的限定下,全域元素/屬性聲明和局部元素/屬性聲明有著不同的使用方式和作用,介紹了他們在同一目標命名空間中不同定位,同時就目標命名空間的特殊使用方式作了介紹。

模式文檔可以被看做一個類型定義和元素宣告的集合(詞彙表),他們的名字被歸屬於一個指定的命名空間,這個命名空間稱為目標命名空間。目標命名空間使我們能夠從不同的詞彙表中區分定義以及聲明。舉例來說,目標命名空間使我們能夠區分在XML Schema 語言詞彙表中的元素宣告和在一個其他是麼的假定的化學語言詞彙表中的元素宣告。前者使目標命名空間"http://www.w3.org/2001/XMLSchema"的一部分,而後者則是另外一個命名空間。

當我們想去檢查一個執行個體文檔是否與一個或者多個模式文檔相符合(通過一個稱為模式校正的處理),我們需要確定在模式定義中聲明和定義的哪些元素和屬性應該被用來檢查在執行個體文檔中的元素和屬性。在這個處理流程中,目標命名空間扮演了一個非常重要的角色。

模式文檔的作者也有幾種可選的方式來影響元素和屬性的標識符如何在執行個體文檔中表現。更特別的,通過使用明確的或者預設的命名空間首碼,作者能夠決定在執行個體文檔中出現的局部的聲明元素和屬性是否必須通過一個命名空間的約束驗證。模式文檔的作者就關於局部元素和屬性的約束的選擇與模式文檔的結構以及針對執行個體文檔的考慮有著很多的牽連,在後面的小節中我們就其中的幾個重要方面進行闡述。

目標命名空間和未限定局部元素/屬性

在新版本的定購訂單模式文檔po1.xsd中(相對於前面的那篇文章XML Schema初步中的po.xsd),我們明確的聲明了一個目標命名空間,並且指明局部定義的元素和屬性必須是為無限定的。在po1.xsd中的目標命名空間為"http://www.example.com/PO1",顯示為屬性targetNamespace的值。

局部元素和屬性的限定能夠在全域指定,這是通過schema元素的一對屬性,elementFormDefault和attributeFormDefault來實現的。而另一種方式,則是單獨地在每個局部聲明中使用form屬性指明。所有類似的屬性值可以被設為"unqualified"或者"qualified",來指出局部聲明的元素和屬性是否必須為無限制的。

在po1.xsd中,通過設定elementFormDefault 和attributeFormDefault為"unqualified",我們在全域的層級指明了元素和屬性的限定。嚴格的說,這些設定並不必須,因為這兩個屬性的預設值就是這個。我們在這裡聲明他們是為了突出這個應用方式和後面我們描述的情形之間的對比:

<schema xmlns="http://www.w3.org/2001/XMLSchema"        xmlns:po="http://www.example.com/PO1"        targetNamespace="http://www.example.com/PO1"        elementFormDefault="unqualified"        attributeFormDefault="unqualified"> <element name="purchaseOrder" type="po:PurchaseOrderType"/> <element name="comment"       type="string"/> <complexType name="PurchaseOrderType">  <sequence>   <element name="shipTo"    type="po:USAddress"/>   <element name="billTo"    type="po:USAddress"/>   <element ref="po:comment" minOccurs="0"/>   <!-- etc. -->  </sequence>  <!-- etc. --> </complexType> <complexType name="USAddress">  <sequence>   <element name="name"   type="string"/>   <element name="street" type="string"/>   <!-- etc. -->  </sequence> </complexType> <!-- etc. --></schema>

為了查看這個模式文檔的目標命名空間是如何被填充的,我們應當依次檢查每一個類型的定義和元素的聲明。在schema元素結束之前,我們首先定義了一個類型USAddress,它由元素name、street等等組成。這種類型定義的一個結果是USAddress類型必須包含在模式文檔的目標命名空間中。然後,我們定義類型PurchaseOrderType,這個類型由元素shipTo、billTo、comment等等組成。PurchaseorderType也包括在模式文檔的目標命名空間中。注意到在這三個元素宣告中的類型引用是有首碼的,po:USAddress。po:USAddress和po:comment,同時這個命名空間首碼是和命名空間”http://www.example.com/PO1”相聯絡的。這個命名空間與這個模式文檔的目標命名空間是同一個命名空間。所以這個模式文檔的處理者將知道在本模式文檔中尋找類型USAddress的定義以及元素comment的聲明。當然,我們也可以通過使用不同的目標命名空間引用其他模式中的類型。因此,這樣就可以在模式文檔中重用外部的定義和聲明。

在模式文檔po1.xsd的開始,我們聲明了元素purchaseOrder和comment,他們包含在模式文檔的目標命名空間中。purchaseOrder元素類型是有命名空間首碼的。同樣USAddress也是有命名空間首碼的。與之相反,comment元素類型、string沒有命名空間首碼。po1.xsd模式文檔包括一個預設的命名空間聲明,因此沒有命名空間首碼的類型諸如string,元素諸如element.和complexType都是與預設的命名空間”http://www.w3.org/2001/XMLSchema”相關聯的。實際上,這是XML Schema自身的目標命名空間,所以一個po1.xsd的處理者知道在XML Schema中尋找類型string的定義和元素element.的聲明。現在,讓我們來審閱一下這個模式文檔的目標命名空間是如何影響一個執行個體文檔的一致性的:

<?xml version="1.0"?><apo:purchaseOrder xmlns:apo="http://www.example.com/PO1"                   orderDate="1999-10-20">    <shipTo country="US">        <name>Alice Smith</name>        <street>123 Maple Street</street>        <!-- etc. -->    </shipTo>    <billTo country="US">        <name>Robert Smith</name>        <street>8 Oak Avenue</street>        <!-- etc. -->    </billTo>    <apo:comment>Hurry, my lawn is going wild!</apo:comment>    <!-- etc. --></apo:purchaseOrder>

在這個執行個體文檔中聲明了一個命名空間"http://www.example.com/PO1"並且把它和命名空間首碼"apo:"相聯絡。這個首碼是用於限定文檔中的兩個元素purchaseOrder 和comment的。這個命名空間和在po1.xsd中模式文檔的目標命名空間是一致的。因此一個執行個體文檔的處理者將知道應當在模式文檔po1.xsd中尋找purchaseOrder和comment的聲明。實際上,目標命名空間這樣命名的原因就是因為對purchaseOrder和comment存在一個目標的命名空間。在模式文檔中的目標命名空間從而控制了在執行個體文檔中相應命名空間的校正。

首碼"apo:"被應用於全域元素purchaseOrder和comment。此外,elementFormDefault和attributeFormDefault要求這個命名空間首碼不是用在局部聲明的每一個元素中,如shipTo、billTo、name和street,並且也不是用在任何一個屬性中(屬性都是局部聲明的)。purchaseOrder和comment都是全域元素,因為他們整體上都是作為schema元素的直接子項目而存在的,而不是在一個特殊類型的內容中聲明的。舉例來說,在po1.xsd中,purchaseOrder的聲明是作為schema元素的一個直接子項目出現的,然而shipTo的聲明是作為類型定義PurchaseOrderTYpe的complexType元素的子項目出現的。

當局部元素和屬性不需要被限定的時候,一個執行個體文檔的作者需要知道或多或少的關於模式文檔的細節來能建立模式文檔,從而校正執行個體文檔。更特殊的,如果作者能夠限定只有根項目(如purchaseOrder)是全域的,那麼只需要簡單的限定根項目。與之相對,作者也許知道所有的元素都是全域聲明的,因此執行個體文檔中所有的元素都能夠被加上命名空間首碼,也許此時會利用預設的命名空間聲明。另外一方面,如果全域和局部的聲明沒有統一的模式,則作者需要瞭解模式的細節來正確的對全域的元素和屬性加上合適的命名空間首碼。



回頁首

限定的局部元素和屬性

雖然在一開始,我們可以描述局部元素的限定方式,然而,元素和屬性仍然是可以被要求被獨立地限定。為了指定所有在模式文檔中局部聲明的元素必須被限定,我們可以通過設定elementFormDefault的值為"qualified"來實現:

<schema xmlns="http://www.w3.org/2001/XMLSchema"        xmlns:po="http://www.example.com/PO1"        targetNamespace="http://www.example.com/PO1"        elementFormDefault="qualified"        attributeFormDefault="unqualified"> <element name="purchaseOrder" type="po:PurchaseOrderType"/> <element name="comment" type="string"/> <complexType name="PurchaseOrderType">  <!-- etc. --> </complexType> <!-- etc. --></schema>

在這個與上述模式文檔相一致的執行個體文檔中,我們明確的限定了所有的元素:

<?xml version="1.0"?><apo:purchaseOrder xmlns:apo="http://www.example.com/PO1"                   orderDate="1999-10-20">    <apo:shipTo country="US">        <apo:name>Alice Smith</apo:name>        <apo:street>123 Maple Street</apo:street>        <!-- etc. -->    </apo:shipTo>    <apo:billTo country="US">        <apo:name>Robert Smith</apo:name>        <apo:street>8 Oak Avenue</apo:street>        <!-- etc. -->    </apo:billTo>    <apo:comment>Hurry, my lawn is going wild!</apo:comment>    <!-- etc. --></apo:purchaseOrder>

當然,我們也可以對每個元素使用預設命名空間提供的隱含限定來代替明確的顯式限定,這就像在下面的po2.xml中所顯示的那樣:

<?xml version="1.0"?><purchaseOrder xmlns="http://www.example.com/PO1"                  orderDate="1999-10-20">    <shipTo country="US">        <name>Alice Smith</name>        <street>123 Maple Street</street>        <!-- etc. -->    </shipTo>    <billTo country="US">        <name>Robert Smith</name>        <street>8 Oak Avenue</street>        <!-- etc. -->    </billTo>    <comment>Hurry, my lawn is going wild!</comment>    <!-- etc. --></purchaseOrder>

在po2.xml中,執行個體文檔中的所有的元素都屬於一個命名空間,並且命名空間的語句聲明了一個預設的命名空間,這個命名空間應用於執行個體文檔中所有的元素。因此,不需要對任何元素使用明確的顯式首碼。

屬性的限定和元素的限定是非常類似的。如果屬性是被聲明為全域屬性或者attibuteFormDefault被設定成"qualified"的話,那麼屬性就必須被限定,在執行個體文檔中將以帶命名空間首碼的方式出現。一個具備限定的屬性的例子是"xsi:nil",實際上,需要限定的屬性必須明確的加上命名空間首碼,因為XML-Namespaces的說明沒有提供關於屬性的預設命名空間的機制。在執行個體文檔中,屬性可以以不帶首碼的方式出現,屬性並非一定需要要具有限定修飾,一般來說,這是典型的應用情況。

對於這個限定機制,我們迄今為止所描繪的已經涵蓋了在特定目標命名空間中所有局部元素和屬性的聲明方式。同時,我們也能夠通過依靠基本的使用form屬性聲明的方式來限定一個聲明。舉例來說,為了需要在執行個體文檔中限定局部聲明的屬性publicKey,我們可以使用下面的方法來聲明:

<schema xmlns="http://www.w3.org/2001/XMLSchema"        xmlns:po="http://www.example.com/PO1"        targetNamespace="http://www.example.com/PO1"        elementFormDefault="qualified"        attributeFormDefault="unqualified"> <!-- etc. --> <element name="secure">  <complexType>   <sequence>    <!-- element declarations -->   </sequence>   <attribute name="publicKey" type="base64Binary" form="qualified"/>  </complexType> </element></schema>

注意到在上面這個模式文檔中,對於publicKey屬性,我們使用了form屬性,來代替attributeFormDefault的值。同樣,form屬性也能夠被用在元素宣告中。下面是一個與前述模式文檔相一直的執行個體文檔的例子:

<?xml version="1.0"?><purchaseOrder xmlns="http://www.example.com/PO1"               xmlns:po="http://www.example.com/PO1"               orderDate="1999-10-20">    <!-- etc. -->    <secure po:publicKey="GpM7">        <!-- etc. -->    </secure></purchaseOrder>


回頁首

全域聲明與局部聲明

另外一種模式文檔的撰寫風格為:當所有的元素名在一個命名空間中是唯一的時候,那麼就可以建立這樣一個模式文檔,在這個模式文檔中所有的元素都是全域的。這種方式和在DTD中使用的效果是一樣。在下面的例子中,我們修改了最初的po1.xsd,使所有的元素都是全域聲明,注意到在這個例子裡面我們忽略了elementFormDefault 和 attributeFormDefault屬性,這是為了強調突出當只有全域元素和屬性聲明時,他們的值無關痛癢的。

<schema xmlns="http://www.w3.org/2001/XMLSchema"          xmlns:po="http://www.example.com/PO1"          targetNamespace="http://www.example.com/PO1"> <element name="purchaseOrder" type="po:PurchaseOrderType"/> <element name="shipTo"  type="po:USAddress"/> <element name="billTo"  type="po:USAddress"/> <element name="comment" type="string"/>  <element name="name" type="string"/> <element name="street" type="string"/> <complexType name="PurchaseOrderType">  <sequence>   <element ref="po:shipTo"/>   <element ref="po:billTo"/>   <element ref="po:comment" minOccurs="0"/>   <!-- etc. -->  </sequence> </complexType> <complexType name="USAddress">  <sequence>   <element ref="po:name"/>   <element ref="po:street"/>   <!-- etc. -->  </sequence> </complexType> <!-- etc. --></schema>

這個"全域"版的po1.xsd將正確地校正我們的執行個體文檔po2.xml,如同我們在前面所描述過地,這個文檔也能夠由前面那個"qualified"版本po1.xsd進行校正。換句話說,兩個schema方法都能夠正確驗證相同的、帶有預設命名空間的執行個體文檔。從一方面來看,這兩個模式文檔的設計方法是相近的,當然從另一方面來看,這兩個模式文檔的撰寫方式又有著非常大的差異。特別是,當所有的元素都被聲明為全域元素時,就不能利用到局部命名的優點。舉例來說,對於全域元素而言,你只能夠聲明一個全域元素"title"。然而對於局部元素而言,你能夠聲明局部元素"title",它有一個string類型,而且它是"book"的子項目。在同樣的模式文檔中(具有相同的目標命名空間),你能夠聲明第二個也叫"title"的元素,它可帶有枚表值"Mr Mrs Ms"。



回頁首

未聲明的目標命名空間

在前面的XML Schema初步這篇文章中,我們使用沒有聲明目標命名空間的模式文檔和沒有聲明命名空間的執行個體文檔來闡述了XML Schema的基本知識。那麼此時,自然而然地會產生一個問題,在這些模式文檔和執行個體文檔的例子裡面目標命名空間是什麼並且他們引用哪裡?

在購買訂單模式文檔po.xsd中,我們沒有為模式文檔聲明一個目標命名空間,我們也沒有聲明與模式文檔目標命名空間相關聯的命名空間首碼(如上面的"po:"),一般來說,如果有命名空間首碼的話,我們就可以在這個命名空間中查閱到模式文檔中的類型和元素的定義和聲明。如果在模式文檔不聲明目標命名空間,那麼其結果就是在這個模式文檔中的定義和聲明,如USAddress和purchaseOrder都是沒有命名空間修飾限定的引用。換句話說,即沒有明確的命名空間首碼應用於引用,同時也沒有任何預設的命名空間隱含地應用於引用。對於當前這個例子來說,purchaseOrder元素引用了類型PurchaseOrderType定義來實施聲明。與之相對,在po.xsd中使用的所有XML Schema元素和類型都是通過與XML Schema命名空間相關聯的命名空間首碼"xsd:"所明確進行限定的。

在模式文檔被設計為沒有目標命名空間的場合下,我們強烈推薦所有的XML Schema元素和類型通過一個和XML Schema命名空間相關聯的命名空間首碼如"xsd:"來明確實施限定(如在po.xsd中)。我們這樣推薦的基本原理是因為如果XML Schema元素和類型預設地與XML Schema命名空間相聯絡,比如不使用命名空間首碼,那麼XML Schema類型的引用也許不能和使用者自訂類型的引用相區別。

使用一個不帶有目標命名空間的模式文檔中的元素宣告可以去驗證在執行個體文檔中沒有命名空間首碼限定的元素。也就是說,他們可用於驗證未被提供命名空間限定的元素,這些元素即沒有明確的命名空間首碼,也沒有預設的命名空間首碼。所以,為了驗證一個傳統的更本未使用命名空間的XML 1.0文檔,你必須提供一個沒有目標命名空間的模式文檔。當然,有很多沒有使用命名空間的XML 1.0文檔,所以將會有很多沒有填寫目標命名空間的模式文檔。



回頁首

小結

本文主要針對XML Schema中的命名空間的使用做了介紹,圍繞命名空間的使用,闡述了模式的範圍以及命名空間對元素/屬性的限定能力。在命名空間的限定下,全域元素/屬性聲明和局部元素/屬性聲明有著不同的使用方式和作用,介紹了他們在同一目標命名空間中不同定位,同時就目標命名空間的特殊使用方式作了介紹。

參考資料

  • Web Service 技術/評論網站

    • WebServices.ORG, Web服務的綜合類技術網站。
    • IBM developerWorks/Web Service Zone, IBM的Web服務技術資源中心
    • MSDN Online Web Services Developer Resources, Microsoft的Web服務的開發人員資源網站

  • Web服務系列技術標準規範
    • XML Schema Part 1: Structures, W3C, 2 May 2001
    • XML Schema Part 2: Datatypes, W3C, 2 May 2001

原文地址:http://www.ibm.com/developerworks/cn/xml/x-schema/part3/index.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.