DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> XML學習教程 >> XML詳解 >> 模式作用域:初級讀本和最佳實踐
模式作用域:初級讀本和最佳實踐
編輯:XML詳解     

模式 是一個格式良好的 XML 文檔,它使用強大的 XML 模式定義語言(XSDL,有時也叫做 W3C Schema)來建模和驗證其他 XML 數據。根據您是如何定義的,模式粒子(元素、類型、屬性和其他構造)都具有一個相關的作用域,可以是全局/暴露的,也可以是局部/隱藏的。模式的作用域設計極大地影響了模式可以如何被改進、重用以及與其他技術協作。

  無論您是剛開始使用模式,還是想要更大地發揮當前解決方案的作用,理解模式作用域都是您成功的關鍵。在本文中,我們首先展示如何為各種模式粒子定義全局或局部作用域,並解釋作用域將如何影響它們的行為。然後我們將描述基本的模式設計范式,並將探索創建滿足項目需求的作用域設計方面的考慮因素和最佳實踐。

  常用縮略詞

  W3C:萬維網聯盟

  XML:可擴展標記語言

  XSDL:XML 模式定義語言

  定義全局作用域元素

  模式的最高層容器元素是 schema。schema 元素的直接子元素是全局定義的(就是說,具有全局作用域)。您可以使用全局元素作為根節點,並且可以從模式的其他部分引用它們。元素只要定義一次,您然後就可以在整個模式中使用它。

  清單 1 中的模式例子展示了一個簡單的數據模型,帶有一個名叫 postalCode 的全局元素:

清單 1. 帶有單個全局元素的模式

<xs:schema> 
 <xs:element name='postalCode' type='xs:string'/> 
</xs:schema> 

  可以使用 清單 1 中的模式來成功地驗證以下數據實例:

<postalCode>14534</postalCode> 

  在這個數據實例中,postalCode 是 根元素 — 即數據實例中的最高層容器。只有在相關模式的最高層定義的元素才可以充當數據實例中的根元素。清單 1 中的模式只定義了一個元素,所以很容易理解只有 postalCode 可以充當實例中的根元素。

 清單 2 中的例子模式在根層次定義了兩個元素:

清單 2. 帶有兩個可能根元素的模式

<xs:schema> 
 <xs:element name='postalCode' type='xs:string'/> 
 <xs:element name='zipCode' type='xs:string'/> 
</xs:schema> 

  postalCode 或 zipCode 都可以充當 清單 2 中模式所建模的實例中的根元素。

  定義局部作用域元素

  將元素定義為局部的可以防止它們被暴露給模式的其他部分。局部元素的上下文局限於它的當前位置,所以不能從模式的其他部分引用它。在 清單 3 的例子中,zipCode 元素不是全局定義的。相反,它被作為 address 元素的子元素,定義在一個元素定義的 complexType 中。

清單 3. 單個帶有局部子元素的全局元素

<xs:schema> 
<xs:element name='address'> 
 <xs:complexType> 
 <xs:sequence> 
  <xs:element name='street' type='xs:string'/> 
  <xs:element name='city' type='xs:string'/> 
  <xs:element name='state' type='xs:string'/> 
  <xs:element name='zipCode' type='xs:string'/> 
 </xs:sequence> 
 </xs:complexType> 
</xs:schema> 

  由於 zipCode 元素的定義位於 address 元素的聲明中,所以它是一個局部定義,它的作用域只在 address 元素中。對於有效的文檔實例,zipCode 元素必須出現在 address 元素中,如 清單 4 所示:

清單 4. 清單 3 中模式的有效數據實例

<address> 
 <!-- street, city and state hidden for example purposes --> 
 
 <zipCode>14534</zipCode> 
</address> 


 

 在 清單 4 中,address 元素是根元素。zipCode 元素不能充當實例中的根元素,因為它不是在模式模塊中的根層次被全局定義的。局部定義的元素只能出現在定義它們的元素定義上下文中。

  在局部作用域內引用全局元素和屬性

  除了充當根元素之外,任何全局定義的元素也可以在任何需要它們的局部作用域內被引用和出現。在 清單 5 的例子中,全局定義的 zipCode 元素被用於局部作用域上下文中的 address 元素的定義中:

清單 5. 局部作用域內引用的全局元素

<xs:schema> 
 <xs:element name="address"> 
 <xs:complexType> 
  <xs:sequence> 
  <xs:element name='street' type='xs:string'/> 
  <xs:element name='city' type='xs:string'/> 
  <xs:element ref='zipCode'/> <!-- reference to globally defined element --> 
  </xs:sequence> 
 </xs:complexType> 
 </xs:element> 
 
<!-- Globally defined element that is referenced in element above --> 
 <xs:element name='zipCode' type='xs:string'/> 
</xs:schema> 

  您可以看到,全局暴露的元素聲明支持模塊化和重用。您可以在該模式的其他部分和會導入該模式的父模式中引用 zipCode 元素。

  屬性定義與此類似。例如,在 清單 6 中,全局定義的 state 被引用在局部作用域上下文中的 address 元素中:

清單 6. 局部作用域中引用的全局屬性

<xs:schema> 
 <xs:element name='address'> 
 <xs:complexType> 
  <!--[.. elements removed for readability..]--> 
  <xs:attribute ref="state"/> <!-- referencing globally defined attribute --> 
 </xs:complexType> 
 </xs:element> 
 
 <xs:attribute name="state" type="xs:string"/> <!--globally defined attribute --> 
 
</xs:schema> 

類型定義

  就跟您可以全局和局部地定義元素和屬性一樣,您也可以這樣定義類型。前面的例子為 address 元素定義使用了局部定義的類型。要讓該類型定義成為全局的,可將它從局部定義刪除,取一個獨特的名稱,並將它放在根 schema 節點下,如 清單 7 所示:

清單 7. 局部作用域內引用的全局類型

<xs:schema> 
 <xs:element name='address' type="address.type"/> 
 
 <xs:complexType name="address.type"> 
  <xs:sequence> 
  <xs:element name='street' type='xs:string'/> 
  <xs:element name='city' type='xs:string'/> 
  <xs:element name='state' type='xs:string'/> 
  <xs:element name='zipCode' type='xs:string'/> 
  </xs:sequence> 
 </xs:complexType> 
</xs:schema> 

  此類型定義現在是全局的了,並且具有獨特的名稱 address.type。要將該類型與一個元素相關聯,我們通過將類型屬性(type="")與全局類型名稱相關聯而引用它。您可以通過使用 xs:extension 元素擴展全局類型定義,也可以通過使用 xs:restriction 元素限制它。

  基本設計范式

  確定應該將模式粒子定義為具有局部作用域還是全局作用域並不總是那麼容易。根據使用情況、名稱空間需求和模式進化等因素,最佳選擇也各不一樣。一般來說,模式設計歸類為四種基本范式:

  Russian doll(俄羅斯套娃)

  Salami slice(意大利香腸片)

  Venetian blinds(軟百葉窗)

  Garden of Eden(伊甸園)

  要為自己的項目確定最佳解決方案,一定要理解這些范式。


 

Russian doll 范式

  該范式來源於著名的俄羅斯套娃(Russian doll)— 一套尺寸由大到小的木頭娃娃,一個套一個地裝在一起。Russian doll 范式局部地定義所有子元素;因此,每個元素及其類型都封裝在其父元素之中,就像俄羅斯套娃那樣。

  清單 8 中的例子 — 一種家電的幫助文檔的簡化表示 — 演示了該范式:

清單 8. Russian doll 風格的模式

<xs:schema> 
<xs:element name="HelpDoc"> 
<xs:complexType> 
 <xs:sequence>   
 <xs:element name="Section">   
  <xs:complexType> 
  <xs:sequence>   
   <xs:element name="Title" type="xs:string"/>   
   <xs:element name="Body" type="xs:string"/> 
  </xs:sequence> 
  <xs:attribute name="name" type="xs:string"/> 
  </xs:complexType> 
 </xs:element> 
 </xs:sequence> 
 <xs:/complexType> 
</xs:element> 
</xs:schema> 

  一個相關的實例類似於 清單 9 這樣。

清單 9. 匹配 Russian doll 模式模型的實例

<HelpDoc> 
 <Section name="Operation_instructions"> 
 <Title>Operating your appliance.</Title> 
 <Body>First, open the packaging and check to see...</Body> 
 </Section> 
</HelpDoc> 

  快速技巧:名稱空間

當一個模式被確定名稱空間時(就是說,具有 targetNamespace),所有全局粒子都必須用全限定名稱進行引用(即 prefix:name)。這樣的名稱空間被稱為是暴露的。例如:

<xs:schema XMLns:xyz="http://xyzcompany.com" 
 targetNamespace="http://xyzcompany.com"> 
  
 <xs:element name="HelpDocs"> 
  <xs:complexType> 
  <xs:sequence>   
   <!--  Global element is referenced,   --> 
      <!--  must contain namespace prefix.   --> 
   <xs:element ref="xyz:Section"/> 
  </xs:sequence> 
  </xs:complexType> 
 </xs:element> 
  
 <xs:element name="Section">   
  <!--    --> 
 </xs:element> 
  
 </xs:schema> 

  由於 Section 元素是全局的,並且聲明了一個 targetNamespace,所以在對 Section 元素的引用中,xyz 名稱空間前綴是必需的。<xs:element ref="Section"/> 不是有效的引用。

  您可以看到,清單 8 中的每個子元素、屬性和類型都是局部定義的。惟一的全局元素是根元素,即 HelpDoc。該語法緊湊,有些人可能會覺得它容易理解。Russian doll 風格的模式不將它們的組件暴露給其他類型、元素或模式,所以它們也被認為是高度去耦的(就是說,元素不全局地依賴於其他元素)和內聚的(相關元素被分組在單個自包含的父元素中)。

  此范式概括為這樣一種模式,即很少有跟其他系統的交互,其組件也沒有重用。通過以這種方式定義模式,您可以保持結構為自包含的、隱藏名稱空間以及防止受到其他系統的影響。

Salami slice 范式

  利用 Salami slice 范式,您可進入暴露內容模型的下一步。在該范式中,您可以將自己所有局部定義的元素都移動到全局定義中。清單 10 展示了 清單 8 中 Russian doll 風格例子修改為滿足 Salami slice 范式後的樣子:

清單 10. Salami slice 范式

<xs:schema> 
 <xs:element name="Body" type="xs:string"/> 
 <xs:element name="Title" type="xs:string"/>  
 
<xs:element name="Section">   
 <xs:complexType> 
 <xs:sequence>   
  <xs:element ref="Title"/>   
  <xs:element ref="Body"/> 
 </xs:sequence> 
 <xs:attribute name="name" type="xs:string"/> 
 </xs:complexType> 
 </xs:element> 
 
 <xs:element name="HelpDocs"> 
 <xs:complexType> 
  <xs:sequence>   
  <xs:element ref="Section"/> 
  </xs:sequence> 
 </xs:complexType> 
 </xs:element> 
</xs:schema> 

  Salami slice 范式暴露所有元素,所以您可以在模式的其他部分引用和重用它們,並且它讓它們對其他模式是透明的。該方法一個主要的優點是,元素高度可重用。但是,這也意味著所有名稱空間都是全局暴露的,並且元素之間的耦合增大了。在 清單 10 中,Section 元素與 Title 和 Body 元素是全局耦合的。對 Title 和 Body 元素的任何修改隨後都會影響 Section 定義。

 Venetian blinds 范式

  在 Venetian blinds 范式中,不是全局地定義所有元素,您首先是全局地定義所有類型,如 清單 11 中的例子所示:

清單 11. Venetian blinds 范式

<xs:schema> 
 <xs:complexType name="section.type"> 
  <xs:sequence>   
  <xs:element name="Title" type="xs:string"/>   
  <xs:element name="Body" type="xs:string"/> 
  </xs:sequence> 
  
  <xs:attribute name="name" type="xs:string"/> 
 </xs:complexType> 
  
 <xs:complexType name="helpdocs.type"> 
  <xs:sequence>   
  <xs:element name="Section" type="section.type"/> 
  </xs:sequence> 
 </xs:complexType> 
  
 <xs:element name="HelpDocs" type="helpdocs.type"> 
  
</xs:schema> 

  Venetian blinds 風格使用全局類型定義來增加重用能力。由於所有子元素都是局部的,所以它額外的優勢是能夠隱藏名稱空間。該方法允許您在使用 elementFormDefault 屬性作為隱藏或暴露名稱空間的一個切換開關的同時,暴露您的結構定義以便重用。您做到了兩全其美!

  Garden of Eden 范式

  在 Garden of Eden 設計范式中,您讓元素聲明和類型聲明都是全局的,將全局化發揮到了極致。清單 12 展示了一個 Garden of Eden 風格的模式:

清單 12. Garden of Eden 范式

<xs:schema> 
 <xs:attribute name="name" type="xs:string"/> 
 <xs:element name="Title" type="xs:string"/>   
 <xs:element name="Body" type="xs:string"/> 
 <xs:element name="Section" type="section.type"/> 
 <xs:element name="HelpDocs" type="helpdocs.type"> 
 
 <xs:complexType name="section.type"> 
 <xs:sequence>   
  <xs:element ref="Title"/>   
  <xs:element ref="Body"/> 
 </xs:sequence> 
 <xs:attribute ref="name"/> 
 </xs:complexType> 
 
 <xs:complexType name="helpdocs.type"> 
 <xs:sequence>   
  <xs:element ref="Section"/> 
 </xs:sequence> 
 </xs:complexType> 
     
</xs:schema> 


 

通過讓每個可能的元素、屬性和類型都成為全局的,您創建了這樣一種場景,即無論是在內部還是在模式之間都最大化了重用 — 盡管是通過強迫名稱空間為暴露的。通過完全暴露您的結構,您讓模式高度耦合卻敏捷。由於元素是相互依賴的,所以很快就會應用大規模的更改。

  最佳實踐:模式管理和改進

  設計模式時,您通常會在暴露可重用組件、隱藏名稱空間和限制名稱空間暴露以及降低耦合(或者叫做多個全局元素/類型之間的相互依賴)之間取得平衡。圖 1 總結了四種模式范式各自的重用潛能,指出了它們耦合和暴露方面的相對等級:

圖 1. 暴露和與不同范式的耦合
模式作用域:初級讀本和最佳實踐

  查看原圖(大圖)

  為重用模式組件提供高潛能可以縮短未來的開發時間和讓大規模更改變得容易。但是,它也會帶來這樣的情況,即多個元素和類型不必要地耦合在一起。當模式變得高度耦合時,元素和類型就變得相互依賴,使得難以管理未來的更改和添加。耦合的猖獗會阻止模式的改進,因為其他系統依賴於您的接口保持一致。對於暴露什麼和暴露多少,一定要謹慎。一旦做出選擇,就難以改變。

  不過,還是有一些方法可以確保未來的成功。首先是適當的作用域設計:

  如果模式重用不是特別重要,而最小化代碼大小卻很必要,那麼請使用 Russian doll 風格,因為它很緊湊,可以用來最大化名稱空間隱藏。

  如果元素替代對於您的設計很重要,或者您需要讓元素對其他模式是透明的,那麼請使用 Salami slice 風格或 Garden of Eden。

 如果您想要高度的重用,還想最大可能地隱藏名稱空間,那麼請使用 Venetian blinds 風格。然後可以使用 elementFormDefault 作為一個切換開關,來要求暴露或隱藏元素。

  此外,不要害怕混用。在特定的模式中使用多種模式設計范式是高度有益的。對於您希望保持為私有和隱藏的結構部分,使用 Russian doll 風格。同時,您也可能想要使用 Salami slice 或 Garden of Eden 設計全局地暴露一些元素。例如,清單 13 使用了高度暴露的 Garden of Eden 風格和隱藏的 Russian doll 風格:

清單 13. 混用范式

<xs:schema> 
 <!-- Garden of Eden style component  --> 
 <xs:element name="Title" type="xs:string"/>   
 <xs:element name="Body" type="xs:string"/> 
 <xs:element name="Section" type="section.type"/> 
 <xs:element name="HelpDocs" type="helpdocs.type"> 
  
 <xs:complexType name="section.type"> 
  <xs:sequence>   
  <xs:element ref="Title"/>   
  <xs:element ref="Body"/> 
  </xs:sequence> 
  
  <xs:attribute name="name"/> 
 </xs:complexType> 
  
 <xs:complexType name="helpdocs.type"> 
  <xs:sequence>   
  <xs:element ref="Section"/> 
  <!--  Russian doll style component  --> 
  <xs:element ref="Credits"> 
   <xs:complexType> 
   <xs:sequence>   
    <xs:element name="Author" type="xs:string"/>   
    <xs:element name="Year" type="xs:string"/> 
   </xs:sequence> 
   </xs:complexType> 
  </xs:element> 
  </xs:sequence> 
 <xs:complexType>    
</xs:schema> 

  在此場景中,也許您需要暴露 HelpDocs、Section、Title 和 Body 元素,以便其他模式使用。但是,您想要隱藏 Credits 元素,以防止它與其他模式定義耦合。

  如果重用的需求不是十分迫切,那麼用這種方式編寫模式是完全合理的。通過讓元素成為全局的,很容易增加暴露。後面去掉暴露將會很困難。在這種情況下,如果未來設計需要更多的暴露,您可以很容易增加。

  結束語

  在開始任何模式項目之前,您必須做出符合自己目標的設計選擇。通過理解模式作用域的使用,可以流水線化管理模式和內容的過程。最終,這將提升您的能力,來管理模式生命周期和讓您的模式高效地與其他系統交互。








 

XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved