DTD 是文檔類型定義(Document Type Definition)的縮寫。DTD 定義了 XML 文檔的結構以及合法的元素和屬性。 為什麼使用 DTD 通過使用 DTD,獨立的團體可以就數據交換的標準 DTD 達成一致。 應用程式可以使用 DTD 來驗證 XML 數據的有效性。 內部 DTD ...
DTD 是文檔類型定義(Document Type Definition)的縮寫。DTD 定義了 XML 文檔的結構以及合法的元素和屬性。
為什麼使用 DTD
通過使用 DTD,獨立的團體可以就數據交換的標準 DTD 達成一致。
應用程式可以使用 DTD 來驗證 XML 數據的有效性。
內部 DTD 聲明
如果 DTD 在 XML 文件內聲明,它必須包裹在 <DOCTYPE>
定義內:
帶有內部 DTD 的 XML 文檔
<?xml version="1.0"?>
<!DOCTYPE note [
<!ELEMENT note (to, from, heading, body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend</body>
</note>
在 XML 文件中,選擇"view source" 以查看 DTD。
上述 DTD 的解釋如下:
<!DOCTYPE note>
定義該文檔的根元素為 note<!ELEMENT note>
定義 note 元素必須包含四個元素:"to, from, heading, body"<!ELEMENT to>
定義 to 元素的類型為 "#PCDATA"<!ELEMENT from>
定義 from 元素的類型為 "#PCDATA"<!ELEMENT heading>
定義 heading 元素的類型為 "#PCDATA"<!ELEMENT body>
定義 body 元素的類型為 "#PCDATA"
外部 DTD 聲明
如果 DTD 在外部文件中聲明,<!DOCTYPE>
定義必須包含對 DTD 文件的引用:
帶有對外部 DTD 引用的 XML 文檔
<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
以下是包含 DTD 的文件 "note.dtd" 的內容:
<!ELEMENT note (to, from, heading, body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
DTD - XML 構建模塊
XML 和 HTML 文檔的主要構建模塊是元素
XML 文檔的構建模塊
從 DTD 的角度來看,所有 XML 文檔都由以下構建模塊組成:
- 元素
- 屬性
- 實體
- PCDATA
- CDATA
元素
元素是 XML 和 HTML 文檔的主要構建模塊。
HTML 元素的示例包括 "body" 和 "table"。XML 元素的示例可能是 "note" 和 "message"。元素可以包含文本、其他元素或為空。空的 HTML 元素的示例包括 "hr"、 "br" 和 "img"。
示例
<body>some text</body>
<message>some text</message>
屬性
屬性提供有關元素的額外信息。
屬性始終位於元素的開始標記內。屬性始終以名稱/值對的形式出現。以下是具有有關源文件的附加信息的 "img" 元素的示例
<img src="computer.gif" />
實體
一些字元在 XML 中具有特殊含義,例如小於號(<),它定義了 XML 標記的開始。
大多數人都知道 HTML 實體: "
"。這個 "no-breaking-space" 實體用於在 HTML 文檔中插入額外的空格。實體在 XML 解析器解析文檔時會被展開。
以下實體在 XML 中是預定義的:
<
代表<
>
代表>
&
代表&
"
代表"
'
代表'
PCDATA
PCDATA 表示解析的字元數據。
將字元數據視為 XML 元素的開始標記和結束標記之間找到的文本。
PCDATA 是解析器將解析的文本。解析器將檢查文本中的實體和標記。
文本內的標記將被視為標記,並且實體將被展開。
但是,解析的字元數據不應包含任何&、<或>字元;這些需要用分別表示為 &
<
和 >
實體。
CDATA
CDATA 表示字元數據。
CDATA 是解析器將不解析的文本。文本內的標記將不被視為標記,並且實體將不被展開。
DTD - 元素
在 DTD 中,元素通過 ELEMENT 聲明進行聲明
聲明元素
在 DTD 中,XML 元素的聲明具有以下語法:
<!ELEMENT element-name category>
或者
<!ELEMENT element-name (element-content)>
空元素
空元素通過 category 關鍵字 EMPTY
進行聲明:
<!ELEMENT element-name EMPTY>
示例
<!ELEMENT br EMPTY>
XML 示例
<br />
具有解析字元數據的元素
僅包含解析字元數據的元素在括弧內使用 #PCDATA
進行聲明:
<!ELEMENT element-name (#PCDATA)>
示例
<!ELEMENT from (#PCDATA)>
具有任何內容的元素
使用 category 關鍵字 ANY
聲明的元素可以包含任意可解析的數據組合:
<!ELEMENT element-name ANY>
示例
<!ELEMENT note ANY>
具有子元素(序列)的元素
具有一個或多個子元素的元素通過在括弧內聲明子元素的名稱進行聲明:
<!ELEMENT element-name (child1)>
或者
<!ELEMENT element-name (child1,child2,...)>
示例
<!ELEMENT note (to,from,heading,body)>
當子元素按逗號分隔在序列中聲明時,子元素必須按相同的順序出現在文檔中。在完整聲明中,子元素也必須被聲明,並且子元素也可以有子元素。 "note" 元素的完整聲明如下:
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
聲明元素的僅出現一次
<!ELEMENT element-name (child-name)>
示例
<!ELEMENT note (message)>
上面的示例聲明瞭子元素 "message" 必須在 "note" 元素內出現一次,且僅一次。
聲明元素至少出現一次
<!ELEMENT element-name (child-name+)>
示例
<!ELEMENT note (message+)>
上面示例中的+號表示子元素 "message" 必須在 "note" 元素內出現一次或多次。
聲明元素出現零次或更多次
<!ELEMENT element-name (child-name*)>
示例
<!ELEMENT note (message*)>
上面示例中的*號表示子元素 "message" 可以在 "note" 元素內出現零次或更多次。
聲明元素出現零次或一次
<!ELEMENT element-name (child-name?)>
示例
<!ELEMENT note (message?)>
上面示例中的?號表示子元素 "message" 可以在 "note" 元素內出現零次或一次。
聲明要麼/或內容
<!ELEMENT note (to,from,header,(message|body))>
上面的示例聲明瞭 "note" 元素必須包含一個 "to" 元素、一個 "from" 元素、一個 "header" 元素,以及一個 "message" 或 "body" 元素。
聲明混合內容
<!ELEMENT note (#PCDATA|to|from|header|message)*>
上面的示例聲明瞭 "note" 元素可以包含零個或多個解析字元數據、"to"、"from"、"header" 或 "message" 元素的出現。
DTD - 屬性
在 DTD 中,使用 ATTLIST 聲明來聲明屬性
聲明屬性
屬性聲明具有以下語法:
<!ATTLIST element-name attribute-name attribute-type attribute-value>
DTD 示例
<!ATTLIST payment type CDATA "check">
XML 示例
<payment type="check" />
attribute-type
可以是以下之一:
CDATA
:值是字元數據(en1|en2|..)
:值必須是列舉列表中的一個ID
:值是唯一標識符IDREF
:值是另一個元素的標識符IDREFS
:值是其他標識符的列表NMTOKEN
:值是有效的 XML 名稱NMTOKENS
:值是有效的 XML 名稱的列表ENTITY
:值是實體ENTITIES
:值是實體的列表NOTATION
:值是符號的名稱xml:
:值是預定義的 xml 值
attribute-value
可以是以下之一:
value
:屬性的預設值#REQUIRED
:屬性是必需的#IMPLIED
:屬性是可選的#FIXED value
:屬性值是固定的
預設屬性值
<!ELEMENT square EMPTY>
<!ATTLIST square width CDATA "0">
有效的 XML
<square width="100" />
在上面的示例中,“square”元素被定義為一個帶有類型 CDATA 的空元素。如果未指定寬度,則其預設值為 0。
REQUIRED
語法
<!ATTLIST element-name attribute-name attribute-type #REQUIRED>
示例
<!ATTLIST person number CDATA #REQUIRED>
有效的 XML
<person number="5677" />
無效的 XML
<person />
如果沒有預設值的選項,但仍希望強制屬性存在,請使用 #REQUIRED
關鍵字。
IMPLIED
語法:
<!ATTLIST element-name attribute-name attribute-type #IMPLIED>
示例
<!ATTLIST contact fax CDATA #IMPLIED>
有效的 XML:
<contact fax="555-667788" />
有效的 XML:
<contact />
如果不想強製作者包含屬性,並且沒有預設值的選項,請使用 #IMPLIED
關鍵字。
FIXED
語法:
<!ATTLIST element-name attribute-name attribute-type #FIXED "value">
示例
<!ATTLIST sender company CDATA #FIXED "Microsoft">
有效的 XML:
<sender company="Microsoft" />
無效的 XML:
<sender company="W3Schools" />
當希望屬性具有固定值而不允許作者更改時,請使用 #FIXED
關鍵字。如果作者包含其他值,XML 解析器將返回錯誤。
列舉屬性值
語法
<!ATTLIST element-name attribute-name (en1|en2|..) default-value>
示例
<!ATTLIST payment type (check|cash) "cash">
XML 示例
<payment type="check" />
或
<payment type="cash" />
當希望屬性值是固定一組合法值之一時,請使用列舉屬性值。
XML 元素與屬性
在 XML 中,沒有規定何時使用屬性,何時使用子元素。
元素與屬性的使用
數據可以存儲在子元素中,也可以存儲在屬性中。
請看以下示例
<person sex="female">
<firstname>Anna</firstname>
<lastname>Smith</lastname>
</person>
<person>
<sex>female</sex>
<firstname>Anna</firstname>
<lastname>Smith</lastname>
</person>
在第一個示例中,sex
是一個屬性。在最後一個示例中,sex
是一個子元素。這兩個示例提供了相同的信息。
在何時使用屬性以及何時使用子元素方面,沒有具體的規則。根據我的經驗,在 HTML 中使用屬性很方便,但在 XML 中應該儘量避免使用。如果信息看起來像是數據,請使用子元素
以下三個 XML 文檔包含完全相同的信息:
- 使用了一個
date
屬性:
<note date="12/11/2002">
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
- 使用了一個
date
元素:
<note>
<date>12/11/2002</date>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
- 使用了擴展的
date
元素(這是我喜歡的):
<note>
<date>
<day>12</day>
<month>11</month>
<year>2002</year>
</date>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
避免使用屬性?
是否應該避免使用屬性?
一些使用屬性的問題包括:
- 屬性不能包含多個值(子元素可以)
- 屬性不容易擴展(用於未來更改)
- 屬性不能描述結構(子元素可以)
- 屬性更難以通過程式代碼進行操作
- 屬性值不容易與 DTD 進行測試
如果將屬性用作數據的容器,最終會得到難以閱讀和維護的文檔。儘量使用元素來描述數據。僅在提供與數據無關的信息時使用屬性。
不要像這樣使用 XML(這不是 XML 的正確用法)
<note day="12" month="11" year="2002"
to="Tove" from="Jani" heading="Reminder"
body="Don't forget me this weekend!">
</note>
關於屬性規則有一個例外:
有時會為元素分配 ID 引用。這些 ID 引用可以用於訪問 XML 元素,方式類似於 HTML 中的 NAME 或 ID 屬性。這個例子演示了這一點:
<messages>
<note id="p501">
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
<note id="p502">
<to>Jani</to>
<from>Tove</from>
<heading>Re: Reminder</heading>
<body>I will not!</body>
</note>
</messages>
這些示例中的 ID 只是一個計數器或唯一標識符,用於識別 XML 文件中不同的 note
,並不是 note
數據的一部分。
這裡想說的是,元數據(關於數據的數據)應該存儲為屬性,而數據本身應該存儲為元素。
實體聲明
實體(Entity)被用來定義對特殊字元的快捷方式。實體可以聲明為內部或外部。
內部實體聲明
語法
<!ENTITY entity-name "entity-value">
示例
DTD示例
<!ENTITY writer "Donald Duck.">
<!ENTITY copyright "Copyright W3Schools.">
XML示例
<author>&writer;©right;</author>
註意:一個實體由三部分組成:一個 &
符號、一個實體名和一個分號。
外部實體聲明
語法
<!ENTITY entity-name SYSTEM "URI/URL">
XML示例
<author>&writer;©right;</author>
DTD示例
電視節目表DTD
<!DOCTYPE TVSCHEDULE [
<!ELEMENT TVSCHEDULE (CHANNEL+)>
<!ELEMENT CHANNEL (BANNER,DAY+)>
<!ELEMENT BANNER (#PCDATA)>
<!ELEMENT DAY (DATE,(HOLIDAY|PROGRAMSLOT+)+)>
<!ELEMENT HOLIDAY (#PCDATA)>
<!ELEMENT DATE (#PCDATA)>
<!ELEMENT PROGRAMSLOT (TIME,TITLE,DESCRIPTION?)>
<!ELEMENT TIME (#PCDATA)>
<!ELEMENT TITLE (#PCDATA)>
<!ELEMENT DESCRIPTION (#PCDATA)>
<!ATTLIST TVSCHEDULE NAME CDATA #REQUIRED>
<!ATTLIST CHANNEL CHAN CDATA #REQUIRED>
<!ATTLIST PROGRAMSLOT VTR CDATA #IMPLIED>
<!ATTLIST TITLE RATING CDATA #IMPLIED>
<!ATTLIST TITLE LANGUAGE CDATA #IMPLIED>
]>
報紙文章DTD
<!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 "Vervet Logic Times">
<!ENTITY PUBLISHER "Vervet Logic Press">
<!ENTITY COPYRIGHT "Copyright 1998 Vervet Logic Press">
]>
產品目錄DTD
<!DOCTYPE CATALOG [
<!ENTITY AUTHOR "John Doe">
<!ENTITY COMPANY "JD Power Tools, Inc.">
<!ENTITY EMAIL "[email protected]">
<!ELEMENT CATALOG (PRODUCT+)>
<!ELEMENT PRODUCT
(SPECIFICATIONS+,OPTIONS?,PRICE+,NOTES?)>
<!ATTLIST PRODUCT
NAME CDATA #IMPLIED
CATEGORY (HandTool|Table|Shop-Professional) "HandTool"
PARTNUM CDATA #IMPLIED
PLANT (Pittsburgh|Milwaukee|Chicago) "Chicago"
INVENTORY (InStock|Backordered|Discontinued) "InStock">
<!ELEMENT SPECIFICATIONS (#PCDATA)>
<!ATTLIST SPECIFICATIONS
WEIGHT CDATA #IMPLIED
POWER CDATA #IMPLIED>
<!ELEMENT OPTIONS (#PCDATA)>
<!ATTLIST OPTIONS
FINISH (Metal|Polished|Matte) "Matte"
ADAPTER (Included|Optional|NotApplicable) "Included"
CASE (HardShell|Soft|NotApplicable) "HardShell">
<!ELEMENT PRICE (#PCDATA)>
<!ATTLIST PRICE
MSRP CDATA #IMPLIED
WHOLESALE CDATA #IMPLIED
STREET CDATA #IMPLIED
SHIPPING CDATA #IMPLIED>
<!ELEMENT NOTES (#PCDATA)>
]>
## 最後
為了方便其他設備和平臺的小伙伴觀看往期文章:
微信公眾號搜索:`Let us Coding`,關註後即可獲取最新文章推送
看完如果覺得有幫助,歡迎點贊、收藏、關註