(本系列文章是我學習的過程中,整理出來的筆記,如有錯漏,看官請一定不吝回復,讓我能認識自己的不足,并改進錯誤。非常感謝!)
本章大概內容:
1、為什么需要DTD
2、XML文檔如何使用DTD
    1)內部定義DTD
    2)關聯外部DTD
3、DTD的結構
    1)元素類型聲明
    2)屬性列表聲明
    3)實體聲明
    4)記號聲明

    對于一個格式良好的XML文檔,我們只能保證這個文檔的格式符合XML規范,但是元素與元素的關系,元素與屬性的關系,屬性的取值,我們就無法保證了。對于一個格式良好的文檔,如果只是在有限的應用中使用,或者是用于存儲和傳輸,那么它也能能夠很好的滿足我們的應用,但是如果要其它的用戶了解你所寫的XML文檔,或者與其它應用進行數據的交換,那么就有必要提供一種機制,來保證我們寫的XML文檔和別人所寫的XML文檔在結構上是相同的,元素與元素之間的關系是正確的,屬性的取值也是符合要求的,那么這種機制在XML規范中已經為我們提供了,那就是前一章中介紹過的文檔類型聲明中提到的DTD。

DTD(Document Type Definition),文檔類型定義。

    在XML標準中,描述了如何創建DTD,以及如何將它與根據它的規范所編寫的XML文檔相關聯,并且還定義了XML處理器應該如何對DTD進行處理。有了DTD就可以檢測XML文檔的結構是否正確。
DTD為XML文檔的編寫者與處理者提供了共同遵循的原則,使得與文檔相關的各種工作有了統一的標準。

如何在XML文檔中引入DTD

通過在XML文檔中包含文檔類型聲明,來建立當前文檔和DTD的關聯。當進行有效性驗證的XML處理器讀到該聲明時,它獲取DTD,并根據其中定義的規則對文檔進行檢驗。文檔類型聲明必須位于XML聲明之后,且在根元素(文檔元素)之前。不過,在XML聲明和文檔類型聲明之間可以插入注釋和處理指令。
我們可以直接在XML文檔中定義DTD,也可以通過URI引用外部的DTD文件,或者同時采用這兩種方式。
上一章中,已經學習過如何通過包含文檔類型聲明來建立與DTD的關聯。現在來分析一下這兩種包含方式。

在XML文檔內部給出DTD的方式:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE OrganizationChart [
    <!ELEMENT OrganizationChart (Name,Office)
>
    
<!ELEMENT Name (#PCDATA)>
    
<!ELEMENT Office (#PCDATA)>
    ]>

<OrganizationChart>
<!--OrganizationChart是該XML文檔的document element-->
    
<Name>Toone,INC.</Name>
    
<Office>zhuhai</Office>
    
<!--因為DTD中定義了Name,Office兩個元素的順序,Office元素不能放在Name元素的前面,否則不是有效的XML文檔-->
</OrganizationChart>
    文檔類型聲明由<!開始,后面緊跟一個關鍵字DOCTYPE,然后是文檔根元素的名字,接下來是標記聲明塊,標記聲明塊放在中括號[]之間,由一個或者多個標記聲明構成,最后由>結束。

    在DTD中,所有的關鍵字都是大寫的。不過,在DTD中定義的元素和屬性的大小寫是可以任意制定的,但是要注意,因為XML文檔是大小寫相關的,所以一旦給一個元素命名,那么在整個文檔中要使用相同的大小寫。例如,organizationchart和OrganizationChart是不同的兩個元素名。

    在XML文檔中定義DTD,比較直觀,修改也比較方便,而且不用擔心XML處理器找不到DTD,但是它也有一些缺點:

    1、在文檔中定義DTD會導致文檔本身的長度增加,在傳輸數據時,即使不需要驗證文檔的有效性,這些聲明也要一起傳輸。

    2、如果多個XML文檔要共用同一個DTD,我們就需要在每一個文檔中加入DTD。


    引進外部DTD方式:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE OrganizationChart SYSTEM "dtdTest.dtd" >
<OrganizationChart>
    
<Name>Toone,INC.</Name>
    
<Office>zhuhai</Office>
</OrganizationChart>
    對應DTD內容為:
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT OrganizationChart (Name,Office)>
<!ELEMENT Name (#PCDATA)>
<!ELEMENT Office (#PCDATA)>

在文檔類型聲明時,用管間質SYSTEM或PUBLIC來指出外部DTD文件的位置,使用SYSTEM關鍵字的聲明語法如下:

<!DOCTYPE 根元素的名字 SYSTEM "外部DTD文件的URI">

SYSTEM關鍵字表示文檔使用的是私有的DTD文件,“外部DTD文件的URI”可以是相對URI或者絕對URI。例如上面的例子使用的就是相對URI:

<!DOCTYPE OrganizationChart SYSTEM "dtdTest.dtd" >

使用PUBLIC關鍵字的聲明語法如下:

<!DOCTYPE 根元素的名字 PUBLIC "DTD的名字" "外部DTD文件的URI">

PUBLIC關鍵字用于聲明公共的DTD,并且這個DTD還有一個名稱,"DTD的名稱"也稱為公共標識符(public identifier)。這個DTD可以存放在某個公共的地方,XML處理程序會根據名稱按照某種方式去檢索DTD,如果XML處理器不能根據名稱檢索到DTD,就會使用"外部DTD文件的URI"來查找該DTD。例如Java web開發的web.xml中的DTD聲明(版本不同會稍有不同,我們只關注它的結構):

<!DOCTYPE web-app PUBLIC '-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN'
'http://java.sun.com/dtd/web-app_2_3.dtd'
>


DTD名稱與XML名稱略有不同,他們只能包含ASCII字母和數字符號、空格、回車符、換行符和一些標點符號:-'()+,/:=?;!#@*$_%.

公共DTD名稱要遵守一些約定。如果一項DTD是ISO標準,它的名稱要以字符串"ISO"開始。如果是一個非ISO的標準組織批準的DTD,它的名字以加號(+)開始。如果不是標準組織批準的DTD,它的名稱以連字符(-)開始。這些開始字符或字符串后接雙斜杠(//)和DTD所有者的名字(比如上面例子的Sun Microsystems,Inc.),之后是另一個雙斜杠和DTD描述的文檔類型,接著優勢一個雙斜杠后接ISO 639語言標識符,如EN表示英語,ZH表示中文。例如:

<!DOCTYPE OrganizationChart PUBLIC "-//Jason Chen//DTD organization chart 1.0//ZH" "dtdTest.dtd">

在上一章我們提到,如果我們的文檔不依賴于外部文檔,在XML聲明中,可以通過standalone="yes"來聲明這個文檔是獨立的文檔。如果文檔依賴于外部文檔,可以通過standalone="no"來聲明。當我們使用外部DTD文件時,就需要將屬性standalone的值設置為"no"。
在實際應用中,很少使用standalone屬性,它的主要用途是作為XML處理器行業其他應用程序的標志,表示是否需要獲取外部內容。如果文檔依賴于外部文檔,即使我們不使用standalone屬性,XML處理器也能很好地進行處理。

DTD的結構:

DTD的結構一般由以下四種聲明構成:
    1、元素類型聲明
    2、屬性列表聲明
    3、實體聲明
    4、記號聲明
一個典型的文檔類型定義文件會吧所要創建的XML文檔的元素結構、屬性類型、實體引用等預先進行定義。
下面分別介紹這四種聲明。

1、元素類型聲明:

一個DTD不僅要告訴XML處理器它所對應的文檔根元素,而且還要告知處理器,文檔的內容和結構,描述清楚文檔結構中的每一個細節。
元素類型聲明不但說明了每一個文檔中可能存在的元素,給出了元素的名稱,而且給出了元素的具體類型。
一個XML元素可以為空,也可以只包含字符數據,還可以有若干個子元素,而這些子元素同時又可以擁有它們的子元素。
元素類型聲明采用如下的語法格式:
<!ELEMENT 元素名稱 元素內容說明>
元素內容說明可以指明五種可能的元素內容形式:#PCDATA、子元素、混合內容、EMPTY和ANY。
下面詳細說明每一種元素內容說明。

#PCDATA:

關鍵字#PCDATA說明元素包含字符數據。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE OrganizationChart [
    <!ELEMENT OrganizationChart (Name,Office)
>
    
<!ELEMENT Name (#PCDATA)>
    
<!ELEMENT Office (#PCDATA)>
    ]>
<OrganizationChart>
    
<Name>Toone,INC.</Name>
    
<Office>ZhuHai</Office>
</OrganizationChart>

子元素:

當一個元素只包含子元素,而沒有字符數據時,則稱此元素類型具有元素型內容(element content)。
在該類型的元素聲明時,通過內容模型來指定在其內容上的約束。內容模型是決定子元素類型和子元素出現順序的一種簡單語法。