官术网_书友最值得收藏!

第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中,任何字符也都可以表示為數字引用。具體方法是在符號“&#”之后加上字符的數字值和分號(它們之間沒有空格)。例如,大于號也可以表示為“&#62;”。

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>&alpha;</letter>
        <description>第一個希臘字母</description>
    </greese>
    <greese>
        <name>beta</name>
        <letter>&beta;</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.&copyright;

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 "人民日報出版社版權所有>
]>
主站蜘蛛池模板: 西吉县| 香格里拉县| 惠州市| 彰化县| 徐州市| 柳河县| 南通市| 新绛县| 藁城市| 合水县| 富源县| 阳春市| 肥城市| 比如县| 来凤县| 陆丰市| 开原市| 吉安市| 秭归县| 九龙城区| 马尔康县| 高淳县| 济源市| 财经| 古蔺县| 乌兰察布市| 九龙城区| 漳州市| 广昌县| 芒康县| 礼泉县| 柳林县| 贺州市| 巴彦淖尔市| 罗平县| 泸西县| 株洲县| 曲水县| 清新县| 井研县| 望都县|