給XML檔案定義DTD

一隻小螞蟻吆發表於2020-04-06

DTD是Document Type Definition(文件型別定義)的縮寫。它通過定義元素、屬性、標記以及文件中的實體及其相互關係等規則來保證XML文件的合法性。

1.DTD的宣告方式分為內部宣告與外部宣告

內部宣告的格式是

<!DOCTYPE 根元素 [

<!ELEMENT 根元素 (元素1,元素2)
>

<!ELEMENT 元素1 (#PCDATA)>

<!ELEMENT 元素2 (#PCDATA)>

]>

外部宣告的格式分兩種,對應的關鍵字為"SYSTEM"與"PUBLIC"

<!DOCTYPE 根元素 SYSTEM "外部DTD檔案">

<!--
 這裡的外部DTD檔案,若不指明 絕對路徑,則必須是和xml檔案在同一目錄,否則無效 --> 

"PUBLIC"宣告的DTD檔案通常是一個由權威機構制訂的,提供給特定行業或公眾使用的DTD。

<!DOCTYPE 根元素 PUBLIC "外部DTD的標示名" "外部DTD檔案路徑">

2.元素型別宣告

<!ELEMENT 元素名 元素內容描述>

 DTD中使用的元素內容型別有:EMPTY、ANY、Mixed、Elements

EMPTY是指元素不能有任何的內容,但可以有屬性:

<!-- DTD宣告部分 --> 

<!ELEMENT 元素1 EMPTY>

<!ATTLIST 元素1 性別 (男|女) "男"> 

<!-- XML檔案部分 -->

<元素1 性別="女" /> 

<!-- 這裡若是以<元素1></元素1>的形式出現,即使裡面沒有任何資料,也會產生錯誤 -->

 ANY說明元素可以有任何型別的子元素,也可以是純文字,還可以為空

<!ELEMENT 元素2 ANY> 

 這裡需要特別注意的是,雖然用ANY定義的元素可以包含其它元素,但必須遵循XML檔案的"有效的"原則,即XML檔案規定檔案中所使用的任何元素都必須在DTD中給出定義

看下面這段非法的檔案:

 

<?xml version="1.0" encoding="gb2312"?>

<!DOCTYPE 圖書資訊 [

<!ELEMENT 圖書資訊 ANY
>

]>

<圖書資訊>

<書名>新概念英語</書名>

</圖書資訊>

編譯器會提示這樣一條錯誤資訊

"This file is not valid: Element '書名' has not been declared."

就是提示"書名"這個元素沒有經過定義,要糾正這個錯誤,只要在DTD定義部分加入定義語句"<!ELEMENT 書名 (#PCDATA)>"就可以了

Mixed允許混合內容使得字元資料和其他元素能在元素內共存,它並不是以關鍵字的形式存在的

<!ELEMENT 元素3 (#PCDATA|子元素1|子元素2)>

 

<?xml version="1.0" encoding="gb2312"?>

<!DOCTYPE 圖書資訊 [
<!ELEMENT 圖書資訊 (#PCDATA|書名|價格)*
>
<!ELEMENT 書名 (#PCDATA)>
<!ELEMENT 價格 (#PCDATA)>
]>

<圖書資訊>
今日新到圖書:
<書名>
XML實用教程
</書名>
<價格>
¥26.00
</價格>
</圖書資訊>

Elements規定特定子元素必須按規則與順序出現,子元素後可以用各種元字元來說明出現的次數

<!ELEMENT 元素4 (子元素1,子元素2,子元素3)>

可能出現的元字元:

元字元 含義
+ 出現1次或多次
* 出現0次或多次
? 出現0次或1次
無符號 只能出現1次

下面的例子中,"IT求職"的各項子元素必須按順序和元字元說明的次數來出現

<?xml version="1.0" encoding="gb2312"?>

<!DOCTYPE IT求職 [
<!ELEMENT IT求職 (招聘資訊)+
>
<!ELEMENT 招聘資訊 (公司名,招聘職位+,公司網站?,聯絡方式*)>
<!ELEMENT 公司名 (#PCDATA)>
<!ELEMENT 招聘職位 (#PCDATA)>
<!ELEMENT 公司網站 (#PCDATA)>
<!ELEMENT 聯絡方式 (#PCDATA)>
]>

<IT求職>

<招聘資訊>
<公司名>中興通訊</公司名>
<!--這裡招聘職位出現了2次-->
<招聘職位>1.Java高階工程師</招聘職位>
<招聘職位>2.C++高階工程師</招聘職位>
<!--這裡公司網站出現了1次-->
<公司網站>http://www.zte.com.cn/</公司網站>
<!--這裡聯絡方式出現了2次-->
<聯絡方式>地址:深圳市南山區高新技術產業園科技南路中興通訊大廈</聯絡方式>
<聯絡方式>電話:0755-26770000</聯絡方式>
</招聘資訊>

<招聘資訊>
<公司名>
阿里巴巴
</公司名>
<!--這裡招聘職位出現了1次-->
<招聘職位>軟體測試工程師</招聘職位>
<!--沒有出現公司網站-->
<!--沒有出現聯絡方式-->
</招聘資訊>

</IT求職>

3.定義有效的元素屬性

在DTD中定義屬性時,我們採用下面的格式:

<!ATTLIST 元素名 屬性名 (屬性值 屬性型別 預設值)*>

例如:

<!ATTLIST 作者

姓名 CDATA #REQUIRED

性別 (男|女) "男"

聯絡方式 CDATA #IMPLIED

>

根據XML檔案是否必須為一個屬性提供取值,屬性的預設值又可以分為以下四類:

  • 必須賦值的屬性REQUIRED
  • 屬性值可有可無的屬性IMPLIED
  • 固定取值的屬性FIXED
  • 自定義的預設值

下面用一個例子來說明這四類預設屬性

<?xml version="1.0" encoding="gb2312"?>

<!DOCTYPE 圖書資訊 [
<!ELEMENT 圖書資訊 (書名,作者,價格)*
>
<!ELEMENT 書名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 價格 (#PCDATA)>
<!ATTLIST 作者 
姓名 CDATA #REQUIRED
性別 (男|女) "男"
聯絡方式 CDATA #IMPLIED
分類 CDATA #FIXED "WEB程式設計技術"
>
]>

<圖書資訊>
<書名>ASP.NET案例開發集錦</書名>
<作者 姓名="趙輝、楊麗敏"/>
<價格>37.00</價格>

<書名>C#高階程式設計</書名>
<作者 姓名="wrox" 聯絡方式="http://www.wrox.com"/>
<價格>128.00</價格>

<書名>HTML XHTML CSS基礎教程(第6版)</書名>
<作者 姓名="Elizabeth Castro" 分類="WEB程式設計技術"/>
<價格>50.00</價格>

<書名>ASP.NET 2.0 應用開發技術</書名>
<作者 姓名="孟憲會(net_lover)" 性別="男"/>
<價格>59.00</價格>
</圖書資訊>

上面的例子為子元素"作者"定義了4個屬性,分別是"姓名"(#REQUIRED型別)、"聯絡方式"(#IMPLIED型別)、"分類"(#FIXED型別)、"性別"(自定義型別)

在第一本書《ASP.NET案例開發集錦》中,只出現了"姓名",但其實際屬性有兩項,還有一個是#FIXED型別的"分類"

在第二本書《C#高階程式設計》中,除了必須出現的"姓名",還出現了#IMPLIED型別的"聯絡方式",算上#FIXED型別的"分類",實際屬性有三項

在第三本書《HTML XHTML CSS基礎教程(第6版》中,除了"姓名",還顯式出現了#FIXED型別的"分類",它的實際屬性與第一本書相同

在第四本書《ASP.NET 2.0 應用開發技術》中,"姓名"後出現了自定義屬性"性別",它只有兩個值"男"和"女",預設為"男",出現其他值將顯示錯誤

屬性型別分為以下10種:

  • CDATA
  • Enumerated
  • ID
  • IDREF
  • IDREFS
  • ENTITY
  • ENTITIES
  • NMTOKEN
  • NMTOKENS
  • NOTATION

CDATA和Enumerated(列舉型別)在上面的例子中已有所說明,主要研究一下其他的屬性型別:

·ID屬性型別

每個ID型別的屬性必須有不同的值,大多數ID屬性使用#REQUIRED,且ID型別和#FIXED不相容.屬性不能既是固定的,又有ID型別.這是因為#FIXED屬性只能有一個值

看下面的錯誤示例:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE 職員資訊 [
<!ELEMENT 職員資訊 (普通職員)*
>
<!ELEMENT 普通職員 (#PCDATA)>
<!ATTLIST 普通職員 編號 ID #REQUIRED>
]>

<職員資訊>
<普通職員 編號="8">張三</普通職員>
<普通職員 編號="E8">李四</普通職員>
<普通職員 編號="E8">王五</普通職員>
</職員資訊>

上面的檔案有2個錯誤,一個是 編號="8" 這裡,ID屬性不能是純數字,必須要以字母或下劃線開頭;另一個是出現了兩個"E8"的編號,這與ID屬性的定義是相違背的.

·IDREF屬性型別

具有IDREF型別的屬性的值是文件中另一個元素的ID

<?xml version="1.0" encoding="gb2312"?>

<!DOCTYPE 武將資訊 [
<!ELEMENT 武將資訊 (姓名)*
>
<!ELEMENT 姓名 (#PCDATA)>
<!ATTLIST 姓名 編號 ID #REQUIRED>
<!ATTLIST 姓名 君主 IDREF #IMPLIED>
]>

<武將資訊>
<姓名 編號="P1">曹操</姓名>
<姓名 編號="P2">劉備</姓名>
<姓名 編號="P3">孫權</姓名>

<姓名 編號="P4" 君主="P1">許楮</姓名>
<姓名 編號="P5" 君主="P2">關羽</姓名>
<姓名 編號="P6" 君主="P3">甘寧</姓名>
</武將資訊>

 

上面的例子中,由於"君主"屬性指定為IDREF,所以其內容必須為ID屬性的"編號"裡的值

·IDREFS屬性型別

IDREF屬性的值只能為一個.但如果要描述一對多的關係,例如三國裡所有人都只有一個君主,但卻會有多個子女.這時候就要用到IDREFS屬性了

<?xml version="1.0" encoding="gb2312"?>

<!DOCTYPE 武將資訊 [
<!ELEMENT 武將資訊 (姓名)*
>
<!ELEMENT 姓名 (#PCDATA)>
<!ATTLIST 姓名 編號 ID #REQUIRED>
<!ATTLIST 姓名 子女 IDREFS #IMPLIED>
]>

<武將資訊>
<姓名 編號="C1">關平</姓名>
<姓名 編號="C2">關興</姓名>
<姓名 編號="C3">孫策</姓名>
<姓名 編號="C4">孫權</姓名>
<姓名 編號="C5">孫尚香</姓名>

<姓名 編號="F1" 子女="C1 C2">關羽</姓名>
<姓名 編號="F2" 子女="C3 C4 C5">孫堅</姓名>
</武將資訊> 

·ENTITY屬性型別

ENTITY型別屬性使人們能把外部二進位制資料(即外部未解析的普通實體)連結到文件,ENTITY屬性的典型例子是一幅影像,該影像由來自與另一個URL的二進位制資料組成

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE 影像 [
<!ELEMENT 影像 EMPTY
>
<!ATTLIST 影像 來源 ENTITY #REQUIRED>
<!ENTITY Logo SYSTEM "logo.gif">
]>
<影像 來源="&Logo;"/>

 

·ENTITIES屬性型別

ENTITIES是ENTITY的複數形式.ENTITIES型別的屬性值由空格分隔多個未解析的實體名稱組成.每個實體名稱引用一個外部的非XML資料來源.這個方法的一個用途是輪流顯示不同圖片的幻燈片,如下所示:

<?xml version="1.0" encoding="gb2312"?>

<!DOCTYPE 幻燈片 [
<!ELEMENT 幻燈片 EMPTY
>
<!ATTLIST 幻燈片 來源 ENTITY #REQUIRED>
<!ENTITY PIC1 SYSTEM "picture1.jpg">
<!ENTITY PIC2 SYSTEM "picture2.gif">
<!ENTITY PIC3 SYSTEM "picture3.jpg">
]>

<幻燈片 來源="&PIC1; &PIC2; &PIC3;"/>

·NMTOKEN屬性型別

NMTOKEN屬性型別限制有效的XML名稱記號的屬性值,除了空格,任何字元都被認為是有效的.

<?xml version="1.0" encoding="gb2312"?>

<!DOCTYPE 客戶資料 [
<!ELEMENT 客戶資料 (聯絡地址)*
>
<!ELEMENT 聯絡地址 (#PCDATA)>
<!ATTLIST 聯絡地址 城市 NMTOKEN #REQUIRED>
]>

<客戶資料>

<聯絡地址 城市="London">張三</聯絡地址>

<聯絡地址 城市="010北京">李四</聯絡地址>

<聯絡地址 城市="New York">王五</聯絡地址>

</客戶資料>

上面的例子,"010北京"雖然是以數字開頭,但由於是NMTOKEN型別,所以它也是合法的.但最後的"New York"為非法,因為NMTOKEN型別限制了空格的使用

·NMTOKENS屬性型別

NMTOKENS是NMTOKEN的複數形式,它允許出現一組值,同NMTOKEN的規則一樣,不限制符號的使用。它可以出現空格,但空格的作用是分割不同的記號

<?xml version="1.0" encoding="gb2312"?>

<!DOCTYPE 註冊資訊 [
<!ELEMENT 註冊資訊 (使用者資料)*
>
<!ELEMENT 使用者資料 (#PCDATA)>
<!ATTLIST 使用者資料 愛好 NMTOKENS #REQUIRED>
]>

<註冊資訊>

<使用者資料 愛好="足球 籃球">張三</使用者資料>

<使用者資料 愛好="唱歌 跳舞">李四</使用者資料>

<使用者資料 愛好="Play the Piano">王五</使用者資料>

</註冊資訊>

上面的例子雖然沒有錯誤,但最後的"play the piano"本來想表達的意思是"彈鋼琴",但由於NMTOKENS的限制,被拆解成了"play"、"the"、"Piano"三個部分。所以在遇到NMTOKENS型別屬性時,要特別注意空格的使用。

·NMTOKENS屬性型別

NOTATION對於使用非XML格式的資料非常有用。現實世界中存在很多無法或不易用XML格式組織的資料,例如圖象、聲音、影像等等。對於這些資料,XML應用程式常常並不提供直接的應用支援。通過為它們設定NOTATION型別的屬性,可以嚮應用程式指定一個外部的處理程式

<?xml version="1.0" encoding="gb2312"?>

<!DOCTYPE 檔案 [
<!ELEMENT 檔案 (聲音檔案)
>
<!ELEMENT 聲音檔案 (#PCDATA)>
<!NOTATION MP SYSTEM "mplayer32.exe">
<!NOTATION ST SYSTEM "soundtool">
<!NOTATION SM SYSTEM "Sound Machine">
<!ATTLIST 聲音檔案 處理程式 NOTATION (MP|SM|ST) #REQUIRED>
]>

<檔案>
<聲音檔案 處理程式="MP">Lydia.mp3</聲音檔案>
</檔案>

相關文章