- Web Services應用開發
- 邵峰晶主編
- 6794字
- 2018-12-26 19:42:01
第2章 XML文檔類型定義
本章目標
■ 了解DTD的作用
■ 掌握內部DTD的使用
■ 掌握外部DTD的使用
■ 掌握DTD的文檔結構
■ 掌握DTD中不同類型元素的定義及使用
■ 掌握DTD中各種屬性的定義及使用
■ 掌握DTD中實體的定義及使用
學習導航
任務描述
【描述2.D.1】
創建并使用內部DTD規范XML文檔。
【描述2.D.2】
創建并使用外部DTD規范XML文檔。
【描述2.D.3】
創建并使用帶屬性的DTD,演示CDATA的使用。
【描述2.D.4】
創建并使用帶NMTOKEN屬性的DTD,演示NMTOKEN的使用。
【描述2.D.5】
創建并使用帶ID屬性的DTD,演示ID的使用。
【描述2.D.6】
創建并使用帶IDREF(IDREFS)屬性的DTD,演示IDREF的使用。
【描述2.D.7】
創建并使用帶枚舉類型屬性的內部DTD,演示枚舉類型的使用。
【描述2.D.8】
創建并使用帶自定義實體的內部DTD,演示自定義實體的使用。
2.1 DTD概述
XML的精髓在于“無障礙”數據交換和數據共享,編寫格式良好的XML文檔,使其他用戶能夠理解符合我們創建的XML詞匯表(包括元素及屬性等)的文檔結構,須通過某種通用的方式說明詞匯表的語法規則。為此,XML1.0提供了一種機制——文檔類型定義(Document Type Definition,DTD),并將其作為規范的一部分。DTD使用正式的語法定義XML文檔的結構和允許值。
2.1.1 DTD簡介
XML的最大靈活性在于允許用戶制定基于信息描述、體現數據之間邏輯關系的自定義標記,確保文檔具有較強的易讀性、清晰的語義和易檢索性。因此,一個完全意義上的XML文檔不僅僅是“Well Formed”(格式良好的),而且還應該是使用了一些自定義標記的“Validating XML”(有效的)文檔,即它必須遵守文檔類型定義DTD中已聲明的各種規定。文檔類型定義DTD,用來描述XML文檔的結構。DTD定義了XML文檔中可用的合法元素,并且定義了可以在文檔中存在的元素、元素可以具有的屬性、元素的層次結構,以及元素在整個文檔中出現的順序。簡而言之,DTD規定了一個語法分析器以解釋一個“Validating XML”文檔所需要知道的所有規則的細節。
DTD可以看做是一個或多個XML文件的模板,這些XML文件中的元素、元素的屬性、元素的排列方式/順序、元素能夠包含的內容等,都必須符合DTD中的定義。XML文件中的元素(標記)是根據應用的實際情況來創建的。想要創建一份完整性高、適應性廣的DTD是非常困難的,因為各行各業都有他們自己的行業特點,所以DTD通常是以某種應用領域為定義的范圍,如:生產、醫學、工商、金融。DTD定義的元素涵蓋范圍越廣泛,它就越復雜。
引入DTD的優勢如下所示。
引入DTD,每個XML文件可以攜帶一個自身格式的描述。
■ 引入DTD,不同組織的人可以使用一個通用DTD交換數據,應用程序可以使用一個標準DTD校驗從外部世界接收來的XML數據是否有效。
■ 引入DTD,便于在網絡上進行數據的共享和交互。例如,兩個相同行業不同地區的人使用同一個DTD文件作為文檔的創建規范,那么他們的數據就很容易交換和共享。網絡上其他用戶補充的數據,只需要根據公用的DTD規范來建立即可。
目前,針對不同的行業和應用,已經有數量眾多的寫好的DTD文件可以利用,這些DTD文件已經建立了通用的元素和標簽規則。用戶無須重新創建,只要在這些DTD文件的基礎上加入特定的新元素即可。當然,用戶也可以創建自己的DTD。
2.1.2 DTD聲明
DTD是與XML文檔相關的。通常,XML文檔中通過DOCTYPE聲明將XML與DTD建立關聯的指令,當驗證有效性的解析器讀到該指令時,它獲取相應的DTD,并根據其中定義的規則對文檔進行校驗。
DOCTYPE聲明由以下部分組成:關鍵字、文檔的根元素名稱、可選的外部標記符,以及可選的標記聲明塊。外部標記符用于外部DTD(外部子集)的命名和定位,標記聲明塊是由標記聲明(內部子集)構成的。
DOCTYPE聲明語法示例如下:
<?xml version="1.0" standalone="no" encode="UTF-8"?> <!DOCTYPE Catalog ...> <Catalog >
第2行中使用“<!DOCTYPE>”標記,該標記就是DOCTYPE聲明,說明該文檔的第一個元素(根元素)是Catalog,省略號“…”隱藏了DOCTYPE聲明的其余部分。
XML規范定義了兩種DOCTYPE聲明的方法。
內部DTD聲明:在DOCTYPE聲明體中直接定義內部標記子集。
■ 外部DTD聲明:用戶可以在獨立的DTD文件中提供外部標記子集聲明,再通過DOCTYPE聲明將其引入。
這兩種聲明方式可以同時使用。
注意 DOCTYPE聲明必須位于XML聲明之后,且在任何文檔元素之前。但是,XML聲明和DOCTYPE聲明之間可以插入注釋和處理指令。
2.1.3 內部DTD
可以使用“<!DOCTYPE[.....]>”語句在XML文檔序言部分聲明DTD文檔的定義,引入內部DTD的XML文檔的語法結構如下:
<?xml version = "1.0" encoding="GB2312"?> <!DOCTYPE element-name[ 元素描述 ]> <!--文檔數據區.......-->
其中:
<!DOCTYPE:表示開始設定DTD,注意DOCTYPE必須大寫。
■ element-name:指定此DTD的根元素的名稱,一個XML文件只能有一個根元素。注意,如果XML文檔使用了DTD,那么文件中的根元素就在這里指定。
■ [ ]>:在[ ]標記里面定義XML文件中使用的元素,然后用“>”結束DTD的定義。
下述代碼用于實現任務【描述2.D.1】,創建并使用內部DTD規范XML文檔。
【描述2.D.1】 student_1.xml
1.<?xml version="1.0" encoding="GB2312"?> 2.<!DOCTYPE students [ 3.<!ELEMENT students (student)+> 4.<!ELEMENT student (name,age,tel)> 5.<!ELEMENT name (#PCDATA)> 6.<!ELEMENT age (#PCDATA)> 7.<!ELEMENT tel (#PCDATA)> 8.]> 9.<students> 10. <student> 11. <name>Tom</name> 12. <age>14</age> 13. <tel>88889999</tel> 14. </student> 15.</students>
上述文檔是一個格式良好,并且有效(滿足DTD校驗)的XML文檔,其中:
* 第1行代碼是一個XML聲明,表示文檔遵循的是XML的1.0版的規范。
* 第2~8行即為內部DTD的定義內容。這個內部DTD中,定義了名為students的元素是XML文檔中的根元素,此根元素擁有至少一個student子元素,子元素student有name、age和tel三個子元素。name、age和tel元素都為“#PCDATA”類型。
注意 在進行DTD書寫時,特別注意元素定義時,需要在元素名稱和內容之間加空格隔開,如:“<!ELEMENT students”和“(student)+>”之間要通過空格隔開。
2.1.4 外部DTD
外部DTD是一個獨立于XML文檔的文件,實際上也是一個文本文件,只是使用.dtd作為文件擴展名。外部DTD獨立于XML文檔,所以它可以供多個XML文件使用,就像用同一個模板可以寫出多個不同內容的文件一樣。
使用外部DTD的好處是:它可以方便高效地被多個XML文檔所共享。只要寫一個DTD文檔,就可以被多個XML文檔所引用。
除了沒有內部DTD中的<!DOCTYPE [.....]>語句外,外部DTD的創建方式、語法和內部DTD是一樣的。XML文檔使用DTD文件的聲明語句來引用創建好的外部DTD文件,此語句必須位于XML文檔的文件序言區,并且要緊跟在XML聲明語句后面,DTD文件的聲明語句格式如下:
<!DOCTYPE type-of-doc SYSTEM/PUBLIC "dtd-name">
具體介紹如下所示。
* <!DOCTYPE:是指要定義一個DOCTYPE。
* type-of-doc:指定文檔類型的名稱,由用戶自己定義,通常與使用這個DTD文件的XML文檔的根元素名稱一致。
* SYSTEM/PUBLIC:這兩個參數只用其一。SYSTEM是指文檔使用的是私有的外部DTD文件,這個關鍵字主要用于引用一個作者或組織所編寫的眾多XML文檔中通用的DTD;而PUBLIC則指文檔調用一個公用的外部DTD文件,此外部DTD文件經過了公開討論,即一個由權威機構制定的、提供給特定行業或公眾使用的DTD。
* dtd-name:是存放DTD文件的地址和名稱。
綜上所述,可以這樣理解引入外部DTD的XML文檔的結構,即:
< ?xml version = "1.0"?> <!DOCTYPE 根元素名 SYSTEM/PUBLIC "外部DTD文件名及其位置"> <!--文檔數據區.......-->
下述代碼用于實現任務【描述2.D.2】,創建并使用外部DTD規范XML文檔。
定義外部DTD文檔內容如下所示。
【描述2.D.2】 student_2.dtd
<?xml version="1.0" encoding="GB2312"?> <!ELEMENT students (student+)> <!ELEMENT student (name,age,tel*)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> <!ELEMENT tel (#PCDATA)>
關聯外部DTD文件的XML的總體代碼如下:
【描述2.D.2】 student_2.xml
<?xml version="1.0" encoding="GB2312"?> <!DOCTYPE students SYSTEM "student_2.dtd"> <students> <student> <name>Tom</name> <age>14</age> <tel>88889999</tel> </student> </students>
上述代碼中,第2行代碼的作用就是將外部DTD文件student_2.dtd應用于此XML文檔。
2.2 DTD語法
DTD是保證XML文檔有效性的方法之一,可使XML解析器通過比較XML文檔和DTD文件來確定文檔是否符合規范、元素和標簽使用是否正確等。一個DTD文檔包含:元素的定義規則、元素間關系的定義規則、元素可使用的屬性以及可使用的實體或符號規則等。DTD文件也是一個ASCII的文本文件,后綴名為.dtd。
2.2.1 元素聲明
元素是XML的核心與靈魂,它包含了實際的文檔信息,并指出了這些信息的邏輯結構。元素以樹形分層機構排列,可以嵌套在其他元素中。
在DTD中,元素類型是通過ELEMENT標記聲明的。除了關鍵字,標記還提供所聲明類型的名稱和內容規范。正如第1章所述,元素類型名要遵守XML對名稱的限制。名稱可以是字母、數字,也可以使用標點符號,如:冒號(:)、下畫線(_)、連字符(-)和句點(.)。然而,名稱不能以數字開頭。它的第一個字符只能是字母、下畫線或冒號。
注意 雖然名稱中可以使用冒號,但是鑒于后面即將介紹的命名空間,最好避免在元素名稱中使用冒號。
DTD中使用元素類型聲明ETD(Element Type Declaration)來聲明所有有效的文檔元素。其語法結構如下:
<!ELEMENT element-name element-definition>
具體介紹如下所示。
* <!ELEMENT:表示開始元素設置,注意此處ELEMENT關鍵字必須是大寫。
* element-name:表示要設置的元素的名稱。
* element-definition:指明要對此元素進行怎樣的定義,就是說<元素>...</元素>之間能夠包含什么內容,是其他元素還是一般性的文字。
XML中按元素的內容(element-definition)可以將元素劃分為五類,不同類型的元素使用DTD進行定義時的語法如下。
1.ANY類型
如果不需要對元素的內容進行限制,可以在DTD中使用ANY元素類型。定義方式為:
<!ELEMENT element-name ANY>
XML文檔里該元素中可以包含任何在DTD中定義的元素內容。建議一般只把文檔的根元素規定為ANY類型。將根元素設為ANY類型后,元素出現的次數和順序不受限制。
注意 為了增強可讀性,每個元素定義通常占據單獨的一行。
2.EMPTY類型
EMPTY元素類型。定義方式為:
<!ELEMENT element-name EMPTY>
這類元素在XML文檔中使用空元素標記,即元素中沒有內容,不能包含子元素和文本,但可以有屬性。例如,對于下面的DTD定義:
<!ELEMENT student EMPTY>
以下這個元素是合法的:
<student name="Jack" age="16"/>
而下面這些元素的定義就是非法的,因為此元素應該為空元素,既不能有內容也不能有子元素:
<student>Jack</student> <student><name>Jack</name></student>
3.#PCDATA類型
#PCDATA類型的元素(純文本元素,或稱簡單元素)可以包含任何字符數據,但是不能在其中包含任何子元素。PCDATA代表字符數據,為防止與關鍵字混淆,需加“#”前綴。其定義方式為:
<!ELEMENT element-name (#PCDATA)>
下面的DTD定義說明name只能包含字符數據,即非標記文本,并且它不能包含自己的子元素:
<!ELEMENT name (#PCDATA)>
下面這些元素定義都是合法的:
<name>Jack</name> <name>2008</name> <name>123.456</name>
因為XML不會去檢查PCDATA的內容,只要是文本就可以。但下面的元素定義是非法的:
<name> <firstname>White</firstname> <lastname>Smith</lastname> </name>
4.父元素類型
父元素類型只能包含子元素,并且這些子元素外沒有文本。這類元素在DTD中通過正則表達式規定子元素出現的順序和次數。語法分析器將這些正則表達式與XML文檔內部的數據模式相匹配,從而判斷該文檔是否是有效的XML。表2-1列出了在DTD中用到的正則表達式的元組運算符。
表2-1 正則表達式的元組運算符
表2-2通過示例介紹了上述元組運算符的用法。
表2-2 用法示例
對于下述DTD定義:
<!ELEMENT students (student+)> <!ELEMENT student (name,age,tel*)>
表明:
students元素是父元素,它可以有至少一個student子元素(由“+”表示);student元素必須有一個name元素、一個age元素、零個或多個tel元素(由“*”表示),而且name、age、tel出現的次序必須一致。
5.混合元素類型
混合元素類型是包含子元素和文本數據的混合體,混合元素的定義方式為:
<!ELEMENT 元素名 (#PCDATA | element-name1 | element-name2 | ……)*>
對于下述DTD定義就是一個混合元素:
<!ELEMENT students (#PCDATA|student)*>
在DTD定義中,帶有字符數據的混合元素只能指定可出現的子元素的名稱,而不能限定它們出現的順序及每個元素的出現次數,或者它們是否出現,嚴重地限制文檔的結構。因此,最好避免使用混合元素。
注意 混合元素在聲明時,其語法結構中除了可以改變子元素數目以外,其他的任何改動都是不合法的。也就是說,不能在包括“#PCDATA”的元素聲明中使用逗號、問號或加號;用豎線分隔的元素和“#PCDATA”的列表是合法的。其他用法是不合法的。
2.2.2 屬性聲明
屬性是對元素的補充和修飾,它能夠將一些簡單的特性與元素相關聯。通過屬性,可以給元素綁定大量信息。例如,在HTML標記IMG中,SRC就是一個屬性。屬性在DTD中是使用ATTLIST標記聲明的。對于含屬性的元素,至少要通過一個ATTLIST標記聲明其屬性列表。ATTLIST聲明由以下部分構成:ATTLIST關鍵字、屬性修飾的元素名稱,以及零個或多個屬性定義。屬性的定義方式為:
<!ATTLIST 元素名 屬性名稱 屬性類型 取值方式 >
實際運用中,一個元素往往不只有一個屬性,當需要為一個元素定義多個屬性時,也可采用如下定義方式:
<!ATTLIST 元素名 屬性名稱 屬性類型 取值方式 屬性名稱 屬性類型 取值方式 ... >
其中,屬性取值方式如表2-3所示。
表2-3 屬性取值方式
屬性類型用來指定該屬性的取值類型,DTD的屬性類型如表2-4所示。
表2-4 屬性類型
下面通過實例,對常用的屬性類型及屬性取值方式進行詳細介紹。
1.CDATA
聲明為CDATA的屬性值可以是任何文本串(包括數字和中文),但不能包含“<”,“&”,“"”等字符串,對于下述屬性聲明:
<!ATTLIST student name CDATA #REQUIRED>
在XML文檔中,下列寫法都是合法有效的:
<student name="Jack"/> <student name="杰克"/> <student name="123456"/>
下述代碼用于實現任務【描述2.D.3】,創建并使用帶屬性的內部DTD,演示CDATA的使用。
【描述2.D.3】 family.xml
<?xml version="1.0" encoding="GB2312"?> <!DOCTYPE family [ <!ELEMENT family (person+, appliance*)> <!ELEMENT person EMPTY> <!ELEMENT appliance EMPTY> <!ATTLIST person name CDATA #REQUIRED age CDATA #REQUIRED tel CDATA #IMPLIED > <!ATTLIST appliance name CDATA #REQUIRED quantity CDATA "1" comments CDATA #IMPLIED > ]> <family> <person name="Rose" age="25"/> <person name="杰克" age="28" tel="88887777"/> <appliance name="冰箱" quantity="2"/> </family>
上述代碼中為person元素聲明了三個屬性:name、age和tel,其中tel可有可無,其他兩個屬性必須出現;為appliance聲明了三個屬性,comments可有可無,name和quantity是必須出現的,并且屬性quantity聲明默認值:1。上述XML文檔合法有效。
如果將XML文檔的XML數據部分寫為如下形式:
<family> <person name="Rose" /> <!-- Error,缺少age屬性--> <person name="杰克" age="28" tel="88887777"/> <appliance name="冰箱" color="red"/><!-- Error,未定義color屬性--> </family>
將提示XML驗證錯誤信息,原因是此XML數據部分聲明未遵循其關聯的DTD文檔規范。
2.NMTOKEN/NMTOKENS
某些情況下,可能希望將屬性值作為標記,代表某種特殊的意義,如:通過標記信息告知解析器對于此文件的處理級別、安全級別等。此時就需要XML中的NMTOKEN(name token,名稱記號),NMTOKEN是CDATA的一個子集,表示屬性值必須是英文字母、數字、句點、連字符、下畫線或冒號組成,即滿足XML名稱規范。
注意 NMTOKEN與元素和屬性名稱并不完全相同,NMTOKEN的第一個字符可以是任意字符,但建議與XML名稱規范一致,方便閱讀。
下述代碼用于實現任務【描述2.D.4】,創建并使用帶NMTOKEN屬性的內部DTD,演示NMTOKEN的使用。
【描述2.D.4】 NMTOKENdemo.xml
<?xml version="1.0" encoding="GB2312"?> <!DOCTYPE poems [ <!ELEMENT poems (poem*)> <!ELEMENT poem (title, content)> <!ATTLIST poem security_level NMTOKEN #REQUIRED> <!ELEMENT title (#PCDATA)> <!ELEMENT content (#PCDATA)> ]> <poems> <poem security_level="all"> <title >黃鶴樓</title> <content> 昔人已乘黃鶴去,此地空余黃鶴樓。黃鶴一去不復返,白云千載空悠悠。 晴川歷歷漢陽樹,芳草萋萋鸚鵡洲。日暮鄉關何處是?煙江波上使人愁。 </content> </poem> </poems>
上述代碼表示元素poem有一個名為security_level的屬性,其值符合XML名稱規則。用戶可以通過該屬性來控制文檔的訪問。由于定義屬性列表時使用了NMTOKEN,用戶只需創建新值就能適應新的安全級別要求,而不必每次都編輯DTD。
NMTOKENS與NMTOKEN類似,是NMTOKEN的復數,每個NMTOKEN之間通過空格隔開。下述代碼演示了NMTOKENS的使用:
<!ATTLIST poem security_level NMTOKENS #REQUIRED> <poem security_level="role1 role2 role5"> …… </poem>
在這里,該poem實例可以被role1、role2和role5訪問。就類型而言,這些數據都是有效的NMTOKEN值。
注意 NMTOKENS的值與枚舉類型不同,解析器不檢查這些NMTOKENS取值的有效性,用戶必須確保自己使用了適當的名稱。
3.ID
ID類型的屬性表明該屬性的取值在整個文檔中必須是唯一的。它可以作為元素的唯一標識符。每個元素至多有一個ID類型的屬性。該ID必須以一個字母開頭。
下述代碼用于實現任務【描述2.D.5】,創建并使用帶ID屬性的內部DTD,演示ID的使用。
【描述2.D.5】 IDdemo.xml
<?xml version="1.0" encoding="GB2312"?> <!DOCTYPE poems [ <!ELEMENT poems (poem*)> <!ELEMENT poem (content)> <!ATTLIST poem NO ID #REQUIRED title CDATA #REQUIRED> <!ELEMENT content (#PCDATA)> ]> <poems> <poem NO="Z001" title="黃鶴樓"> <content> 昔人已乘黃鶴去,此地空余黃鶴樓。黃鶴一去不復返,白云千載空悠悠。 晴川歷歷漢陽樹,芳草萋萋鸚鵡洲。日暮鄉關何處是?煙江波上使人愁。 </content> </poem> <poem NO="Z002" title="望廬山瀑布"> <content> 日照香爐生紫煙,遙看瀑布掛前川。飛流直下三千尺,疑是銀河落九天。 </content> </poem> </poems>
上述文檔的內部DTD將屬性NO聲明為ID類型的,XML的數據部分是合法有效的。如果將兩個元素poem屬性NO的取值都改為“Z001”和“Z002”或分別改為“001”和“002”,這兩種情況都將提示相關的錯誤信息。
注意 ID類型的屬性必須設置為#IMPLIED或#REQUIRED,不能是#FIXED或默認的,不能為ID提供默認值。
4.IDREF/IDREFS
IDREF屬性的值指向文檔中其他地方聲明的ID類型的值。在應用程序中,通過ID和IDREF實現交叉引用,而不必多次重復整個元素。
IDREF屬性的值與ID類型的取值約束一致,而且它必須與文檔中的某個ID屬性具有相同的值。IDREF值不能指向文檔中不存在的ID。IDREFS與IDREF類似,是IDREF的復數,每個IDREF之間通過空格隔開。
下述代碼用于實現任務【描述2.D.6】,創建并使用帶IDREF(IDREFS)屬性的內部DTD,演示IDREF的使用。
【描述2.D.6】 IDREFdemo.xml
<?xml version="1.0" encoding="GB2312"?> <!DOCTYPE family [ <!ELEMENT family (person+)> <!ELEMENT person EMPTY> <!ATTLIST person relID ID #REQUIRED parentID IDREFS #IMPLIED name CDATA #REQUIRED > ]> <family> <person relID="P01" name="Bernie"/> <person relID="P02" name="Rose"/> <person relID="P03" parentID="P01" name="Joson"/> <person relID="P04" name="Tom"/> <person relID="P05" name="Barbara"/> <person relID="P06" parentID="P04 P05" name="Barbie"/> </family>
上述文檔中,通過交叉引用,應用程序(或XML解析器)可以通過元素的parentID屬性找到其引用的person元素。
5.枚舉類型
枚舉類型(Enumerated)不需要使用關鍵字,它只是將所有可能的屬性取值列舉出來,并以豎線(“|”)分隔。枚舉類型的每一個可能值都必須遵循XML的名稱規范。
下述代碼用于實現任務【描述2.D.7】,創建并使用帶枚舉類型屬性的內部DTD,演示枚舉類型的使用。
【描述2.D.7】 ENUMdemo.xml
<?xml version="1.0" encoding="GB2312"?> <!DOCTYPE students [ <!ELEMENT students (student+)> <!ELEMENT student EMPTY> <!ATTLIST student name CDATA #REQUIRED age CDATA #REQUIRED sex (male | female) "male" > ]> <students> <student name="Tom" age="17"/> <student name="Rose" age="19" sex="female"/> </students>
上述文檔中,元素student的sex屬性被聲明為枚舉類型,可能的取值為male或female,并被設置默認取值為male。在實際應用中,元素student的sex屬性的取值必須為上述二者取值之一。
2.2.3 實體
實體(Entity)是XML中一種可以節省大量時間的機制,它的作用類似于Word中的“宏”,也可以將其理解為模板,使用者可以預先定義一個實體,然后在一個文檔中多次調用,或者在多個文檔中調用同一個實體。簡單來說,實體就是XML引用一個數據項的方法,它通常是文本,也可以是二進制數據。
一般情況下,實體的命名遵循XML名稱規范即可,使用實體的好處在于以下兩個方面。
* 減少出錯率,文檔中多個相同的部分只需要輸入一遍即可。
* 提高維護效率,比如多個文檔都包含地址信息的實體,如果需要修改這個地址信息,只要修改最初定義的實體語句即可。
XML定義了兩種類型的實體:一種是預定義實體;另一種是自定義實體。
1.預定義實體
在XML中,對于XML語言定義的某些特殊字符(如尖括號)需保留定義,另外,有些字符是不可打印的。XML提供了一些預定義的實體,如表2-5所示,使用者可以在XML文檔中利用這些實體表示特定的字符,并保證不產生沖突。因此在元素的文本內容中,可以用實體表示一些特殊字符,以免它們在解析時與文檔的標記混淆。
表2-5 XML的預定義實體
在XML中,任何字符也都可以表示為數字引用。具體方法是在符號“&#”之后加上字符的數字值和分號(它們之間沒有空格)。例如,大于號也可以表示為“>”。
2.自定義實體
使用者也可以根據需要在DTD中定義一個實體,然后在文檔中通過引用來使用它。
自定義實體的語法格式為:
<!DOCTYPE rootname [ <!ENTITY entity-name "entity-content"> ]>
下述代碼定義了一段地址信息:
<!DOCTYPE ADDRESS [ <!ENTITY ADDRESS "山東路家樂福"> ]>
如果此地址信息的內容和他人所需的信息來源于同一個文件,也可以使用外部調用的方法。引用格式如下:
<!DOCTYPE ADDRESS [ <!ENTITY ADDRESS SYSTEM "http://www.sample.com/ADDRESS.xml"> ]>
定義好的實體在文檔中的引用語法為“&實體名;”。
下述代碼用于實現任務【描述2.D.8】,創建并使用帶自定義實體的內部DTD,演示自定義實體的使用。
【描述2.D.8】 ENTITYdemo.xml
<?xml version="1.0" encoding="GB2312"?> <!DOCTYPE greeses [ <!ELEMENT greeses (greese+)> <!ELEMENT greese (name, letter, description?)> <!ELEMENT name (#PCDATA)> <!ELEMENT letter (#PCDATA)> <!ELEMENT description (#PCDATA)> <!ENTITY alpha "α"> <!ENTITY beta "β"> ]> <greeses> <greese> <name>alpha</name> <letter>α</letter> <description>第一個希臘字母</description> </greese> <greese> <name>beta</name> <letter>β</letter> <description>第二個希臘字母</description> </greese> <greese> <name>小于號</name> <letter><</letter> </greese> </greeses>
通過IE瀏覽器查看結果如圖2-1所示。

圖2-1 實體顯示結果
需要注意的是,實體允許嵌套,如下述代碼是允許的:
<!ENTITY man "Mr."> <!ENTITY name "Johnson"> <!ENTITY welcome "&man; &name;">
但是,實體不允許循環,如下述代碼是錯誤的:
<!ENTITY man "Mr.&name;"> <!ENTITY name "&man; Johnson">
當XML解析器處理這種情況時,會陷入死循環,用戶在定義實體時,務必要嚴防這種事情的發生。
小結
通過本章的學習,學生應該能夠學會:
* DTD是一套關于標記符的語法規則,是XML 1.0規格的一部分。
* DTD是一種保證XML文檔格式正確的有效方法。
* DTD文件是一個ASCII的文本文件,后綴名為.dtd。
* DTD可以在XML內部定義也可以在外部定義。
* DTD提供了XML文檔所包含的元素、屬性和實體及相互關系的定義。
* DTD的元素類型有ANY類型、EMPTY類型、#PCDATA類型、父元素類型和混合元素類型。
* 常用的DTD屬性類型有CDATA、NMTOKEN/NMTOKENS、ID、IDREF/IDREFS、枚舉類型等。
* XML中實體可以理解為模板,使用者可以預先定義一個實體,然后在一個文檔中多次調用,或者在多個文檔中調用同一個實體。
* 實體是XML引用一個數據項的方法,它通常是文本,也可以是二進制數據。
* XML定義了兩種類型的實體。一種是預定義實體;另一種是自定義實體。
練習
1.下列選項中,______是合法的元素名。
A.TOM B.1abc C.18 D.[abc]
2.對于下面的代碼,______不是PRODUCT元素的子元素。
<!ELEMENT PRODUCT (PRODUCTNAME, DESCRIPTION, PRICE, QUANTITY)>
A.PRODUCTNAME B.QUANTITY
C.DESCRIPTION D.NUMBER
3.DTD文檔中,定義屬性的關鍵字是______。
A.DOCTYPE B.ATTLIST
C.ELEMENT D.ENTITY
4.下列選項中,______是預定義實體(多選)。
A.& B.&name; C.< D.©right;
5.DTD文檔中,某元素屬性的特點為必須包含該屬性,該屬性應定義為______。
A.#REQUIRED B.#IMPLIED
C.#FIXED value D.默認值
6.在DTD中,元素類型通過_________標記聲明,實體類型通過_________標記聲明。
7.DOCTYPE聲明由以下部分組成:_________、_________、可選的外部標記符,以及_________。
8.屬性類型設為ID,表明該屬性的取值_________。
9.XML定義了兩種類型的實體,一種是_________;另一種是_________。
10.IDREF屬性的值指向文檔中其他地方聲明的_________類型的值。
11.分析下列XML實例,上機編寫外部DTD文檔,并進行驗證。
<?xml version="1.0" encoding="GB2312"?> <班級> <學生 學號="C95001"> <姓名>李明</姓名> <性別>男</性別> <年齡>18</年齡> </學生> <學生 學號="C95002"> <姓名>張燕</姓名> <性別>女</性別> <年齡>19</年齡> </學生> <學生 學號="C95003"> <姓名>趙彥</姓名> <性別>男</性別> <年齡>20</年齡> </學生> </班級>
12.分析下列DTD文檔,上機編寫有效的XML實例,并進行驗證。
<!DOCTYPE NEWSPAPER [ <!ELEMENT NEWSPAPER (ARTICLE+)> <!ELEMENT ARTICLE (HEADLINE,BYLINE,LEAD,BODY,NOTES)> <!ELEMENT HEADLINE (#PCDATA)> <!ELEMENT BYLINE (#PCDATA)> <!ELEMENT LEAD (#PCDATA)> <!ELEMENT BODY (#PCDATA)> <!ELEMENT NOTES (#PCDATA)> <!ATTLIST ARTICLE AUTHOR CDATA #REQUIRED> <!ATTLIST ARTICLE EDITOR CDATA #IMPLIED> <!ATTLIST ARTICLE DATE CDATA #IMPLIED> <!ATTLIST ARTICLE EDITION CDATA #IMPLIED> <!ENTITY NEWSPAPER "人民日報"> <!ENTITY PUBLISHER "人民日報出版社"> <!ENTITY COPYRIGHT "人民日報出版社版權所有> ]>