前言
XML允許使用者宣告DTD(Document Type Definition)來指定可以被包含在XML文件中的標籤種類。 DTD必須包含在文件的檔頭(prolog)中,以使XML解析器在一開始執行時便可以知道該份XML文件的格式定義。
基本的 DTD 定義
首先我們建造一個名為 sample.dtd 的檔案,然後輸入一個XML宣告和註解來做為檔案識別,如下所示:
<?xml version='1.0' encoding='Big5'?>
<!-- XML投影片簡報DTD範例 -->
接著,增加下列粗體字部份來定義在"投影片簡報"元素中只能夠包含名為"投影片"的元素:
<?xml version='1.0' encoding='Big5'?>
<!-- XML投影片簡報DTD範例 -->
<!ELEMENT 投影片簡報 (投影片+)>
利用這一行元素宣告我們定義了一個可以包含一或多個"投影片"元素的"投影片簡報"元素。在此讀者們可以看到,一個元素的宣告格式為"<!ELEMENT"啟始符號加上我們所要指定的標籤名稱("投影片簡報"),然後再以刮弧方式加入允許在指定的標籤名稱("投影片簡報")中存在的元素名稱("投影片")及數量,最後使用">"來結束元素的宣告。
如果我們在這一行元素宣告中未加上"+ "符號,這將會導致"投影片簡報"只能含有單一個"投影片"元素。 (表一)中列出我們可以使用來定義元素數量的qualifier(限定詞)。
Qualifier(限定詞) 名稱 所代表意義
? 問號 可選擇的 (零或一)
* 星號 零或多個
+ 加號 一或多個
我們可以在一個刮弧之內以逗點做為分隔符號來允許一個元素包含多個子元素,並且在每個子元素後面加上一個qualifier(限定詞)來宣告每個子元素可以出現的次數。 以逗點分隔的元素列表代表了哪一些元素是允許被使用以及他們可以出現的順序。
定義Text和Nested元素
接下來,增加下面粗體字部份來定義"投影片"、"標題"和"項目"元素:
<?xml version='1.0' encoding='Big5'?>
<!-- XML投影片簡報DTD範例 -->
<!ELEMENT 投影片簡報 (投影片+)>
<!ELEMENT 投影片 (標題, 項目*)>
<!ELEMENT 標題 (#PCDATA)>
<!ELEMENT 項目 (#PCDATA | 項目)*>
在我們所增加的第一行宣告中敘述了每一個"投影片"元素中必須含有一個名為"標題"的元素,而且在"標題"元素之後可以含有零或一個名為"項目"的元素。 第二行宣告則敘述一個"標題"元素包含了可被解析的文字資料parsed character data(PCDATA),也就是一般所謂的純文字(text),但是在XML中它被稱之為"parsed character data"。 PCDATA字串前所使用的"#"代表其接下來的字串(在此為PCDATA)有其特別的意義,而非一個元素名稱。
最後一行宣告中採用了一個直條符號"|",來表示一個"or"條件。 在筆者所使用的範例中,這一個"or"條件表示"項目"元素中可以存有PCDATA或者是另一個名為"項目"的元素。 在結尾的"*"(星號符號)則代表它可出現零或一次以上。 我們可以稱這個規格的結果為一個mixed-content model(混合內容的模型),因為任何數目的"項目"元素均可以與純文字(text)一起散佈。 這樣的模型首先必須定義#PCDATA敘述,接著使用直條符號"|"來分隔其他的項目,最後在結尾加上一個星號(*)。
定義DTD裡的屬性
到這裡為止,筆者已經為各位示範了如何定義一份可使用來敘述XML文件的DTD。 但是由於到目前所完成的DTD只敘述了XML文件內容應出現的位置,因此,這份DTD將只適合被nonvalidating語法解析器來使用。 要讓validating語法解析器能夠使用這一份DTD,我們將需要為各個不同的元素增加有效屬性的敘述。
首先我們增加定義"投影片簡報"元素屬性的DTD,如下列所示:
<?xml version='1.0' encoding='Big5'?>
<!-- XML投影片簡報DTD範例 -->
<!ELEMENT 投影片簡報 (投影片+)>
<!ATTLIST 投影片簡報
標題 CDATA #REQUIRED
日期 CDATA #IMPLIED
講師 CDATA #REQUIRED
>
<!ELEMENT 投影片 (標題, 項目*)>
<!ELEMENT 標題 (#PCDATA)>
<!ELEMENT 項目 (#PCDATA | 項目)*>
如同前面介紹過的元素宣告保留字ELEMENT一樣,ATTLIST標籤為DTD使用來定義一連串屬性的啟始符號。 跟隨在ATTLIST後面的則為包含這些被定義屬性的元素名稱。 在上面的範例中,這個元素為"投影片簡報"。
元素中的每一個屬性是由一連串的三個分隔數值所定義而成。 這三個數值是不允許使用逗點或其他的符號來分隔的,因此,如果將這些屬性定義如上面範例中的格式來排列顯示將增加文件的可讀性。 在每一行屬性定義裡的第一個元素代表的是屬性的名稱,在此依序分別為: "標題"、"日期"及"講師"。 第二個元素所象徵的則是各屬性的資料類型: CDATA代表其內容為文字類型、未解析的(unparsed)資料。 筆者在(表二)中為各位介紹可選擇使用的各屬性類型。
屬性類型 敘述說明
(value1 | value2 | ...) 使用直條符號"|"分隔的數值列表 (範例如後)
CDATA 文字字串資料 (Unparsed character data)
ID 一個沒有其他ID屬性分享的名稱
IDREF 一個參照到相同文件中不同位置的ID索引
IDREFS 一個使用空格來分隔,包含一或多個ID索引的列表
ENTITY 定義在DTD中的實體名稱
ENTITIES 一個使用空格來分隔的實體名稱列表
NMTOKEN 一個由字母、數字、連字號、底線和冒號組成的有效XML名稱
NMTOKENS 一個使用空格來分隔的名稱列表
NOTATION DTD使用來描述一個非XML資料格式的敘述記號名稱,例如:影像檔
當所有可利用的屬性類型被包含在括弧內並以直條符號分隔時,這表示此一個屬性的數值將必需為括弧中的任何一種已定義的數值型態。 舉例來說,當我們增加下列粗體字定義到DTD:
<?xml version='1.0' encoding='Big5'?>
<!-- XML投影片簡報DTD範例 -->
<!ELEMENT 投影片簡報 (投影片+)>
<!ATTLIST 投影片簡報
標題 CDATA #REQUIRED
日期 CDATA #IMPLIED
講師 CDATA #REQUIRED
>
<!ELEMENT 投影片 (標題, 項目*)>
<!ATTLIST 投影片
型態 (管理 | 技術 | 全部) #REQUIRED
>
<!ELEMENT 標題 (#PCDATA)>
<!ELEMENT 項目 (#PCDATA | 項目)*>
這一個新增加的定義表示"投影片"元素的"型態"屬性必需設定為: 型態="管理"、型態="技術"或是型態="全部"。 所有其他的型態數值均是不被接受的設定。
屬性定義裡的最後一個項目敘述此一屬性的預設值,而且告知此屬性是否是必要的。 (表三)中列出目前所有可被選擇使用的屬性預設值。
規格 敘述說明
#REQUIRED 該元素必須要設定該屬性的屬性值
#IMPLIED 該元素不一定要設定該屬性的屬性值。
如果它未被敘述定義,應用程式將會使用預設的數值。
"defaultValue" 一個沒有其他ID屬性分享的名稱
#FIXED "fixedValue" 一個參照到相同文件中不同位置的ID索引
讓XML文件參照DTD
在筆者的範例中,DTD定義與XML文件是分開儲存於各別的檔案中。 我們可以增加下面粗體字部份到需要使用DTD的XML文件sample.xml(內容如下所列)中,使解析器在解析它時能參照到我們剛剛建立的DTD格式定義檔案sample.dtd:
<?xml version='1.0' encoding='Big5'?>
<!DOCTYPE 投影片簡報 SYSTEM "sample.dtd">
<!-- XML投影片簡報格式示範 -->
<投影片簡報 標題="簡短的投影片簡報" 日期="簡報日期" 講師="王泳泰">
<!-- 投影片 標題 -->
<投影片 型態="全部">
<標題>XML應用</標題>
</投影片>
<!-- 投影片 概觀 -->
<投影片 型態="全部">
<標題>概觀</標題>
<項目>何謂 <em>XML</em>? </項目>
<項目/>
<項目><em>產業</em>XML化</項目>
</投影片>
</投影片簡報>
在上列加入的指令中,"<!"為DTD標籤的啟始符號。 接著,標籤名稱DOCTYPE敘述此文件為一份"投影片簡報",其意思表示此文件的根元素名稱為"投影片簡報"以及所有其他資訊(例如:"投影片"元素)均包含在這個根元素"投影片簡報"之內:
<投影片簡報>
...
</投影片簡報>
DOCTYPE標籤必須撰寫在XML檔案宣告之後及根元素之前。 而SYSTEM識別符號則是用來敘述DTD檔案所在的位置。 由於它的起頭並不是http:/ 或 file:/,因此其路徑將連結到與XML文件相同的目錄位置中。 另外,一個PUBLIC識別符號也能夠被使用來替代SYSTEM識別符號,PUBLIC識別符號將允許我們以unique name(唯一名稱)來敘述DTD檔案的位置。
DOCTYPE規格並且也能夠讓使用者將DTD定義直接包含在所需的XML文件中,如此我們將無須再參照XML文件到外部的DTD檔案。 這樣的定義將需要被撰寫在square brackets(正方形括弧)中,其架構如下:
<!DOCTYPE 投影片簡報 SYSTEM "sample.dtd" [
...這裡是DTD定義所撰寫位置...
]>
如果我們將上面的外部DTD範例修改為內部DTD,其格式架構將如下所示(下列粗體字部分為我們所自訂的DTD內容):
<?xml version='1.0' encoding='Big5'?>
<!DOCTYPE 投影片簡報 [
<!-- XML投影片簡報DTD範例 -->
<!ELEMENT 投影片簡報 (投影片+)>
<!ATTLIST 投影片簡報
標題 CDATA #REQUIRED
日期 CDATA #IMPLIED
講師 CDATA #REQUIRED
>
<!ELEMENT 投影片 (標題, 項目*)>
<!ATTLIST 投影片
型態 (管理 | 技術 | 全部) #REQUIRED
>
<!ELEMENT 標題 (#PCDATA)>
<!ELEMENT 項目 (#PCDATA | 項目)*>
]>
<!-- XML投影片簡報格式示範 -->
<投影片簡報 標題="簡短的投影片簡報" 日期="簡報日期" 講師="王泳泰">
<!-- 投影片 標題 -->
<投影片 型態="全部">
<標題>XML應用</標題>
</投影片>
<!-- 投影片 概觀 -->
<投影片 型態="全部">
<標題>概觀</標題>
<項目>何謂 <em>XML</em>? </項目>
<項目/>
<項目><em>產業</em>XML化</項目>
</投影片>
</投影片簡報>
結論
在介紹了DTD符號的使用方法之後,我們就可以開始試著為自己的XML文件定義DTD,這時您將會實際體驗到DTD的實用性。