探索 DTD 在 XML 中的作用及解析:深入理解文檔類型定義

来源:https://www.cnblogs.com/xiaowange/p/18160894
-Advertisement-
Play Games

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 實體: "&nbsp;"。這個 "no-breaking-space" 實體用於在 HTML 文檔中插入額外的空格。實體在 XML 解析器解析文檔時會被展開。

以下實體在 XML 中是預定義的:

  • &lt; 代表 <
  • &gt; 代表 >
  • &amp; 代表 &
  • &quot; 代表 "
  • &apos; 代表 '

PCDATA

PCDATA 表示解析的字元數據。

將字元數據視為 XML 元素的開始標記和結束標記之間找到的文本。

PCDATA 是解析器將解析的文本。解析器將檢查文本中的實體和標記。

文本內的標記將被視為標記,並且實體將被展開。

但是,解析的字元數據不應包含任何&、<或>字元;這些需要用分別表示為 &amp; &lt;&gt; 實體。

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 文檔包含完全相同的信息:

  1. 使用了一個 date 屬性:
<note date="12/11/2002">
  <to>Tove</to>
  <from>Jani</from>
  <heading>Reminder</heading>
  <body>Don't forget me this weekend!</body>
</note>
  1. 使用了一個 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>
  1. 使用了擴展的 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;&copyright;</author>

註意:一個實體由三部分組成:一個 & 符號、一個實體名和一個分號。

外部實體聲明

語法

<!ENTITY entity-name SYSTEM "URI/URL">

XML示例

<author>&writer;&copyright;</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`,關註後即可獲取最新文章推送

看完如果覺得有幫助,歡迎點贊、收藏、關註

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文介紹基於Microsoft SQL Server軟體,實現資料庫表的創建、修改、複製、刪除與表數據處理的方法。 目錄1 互動式創建資料庫表T2 互動式創建資料庫表S3 T-SQL創建資料庫表C4 T-SQL創建資料庫表SC5 T-SQL創建資料庫表TC6 互動式向資料庫表S中添加新列NATIVE ...
  • 字元編碼和排序規則 下麵的討論用到W、王和三個字元,以下是這三個字元的各種編碼 先看看不帶N和帶N的字元字面量各用什麼編碼,用Microsoft SQL Server Management Studio連接SQL SERVER 2022執行下麵SQL語句: select N'W' charact ...
  • 引言 在數據驅動的世界中,企業正在尋求可靠且高性能的解決方案來管理其不斷增長的數據需求。本系列博客從一個重視數據安全和合規性的 B2C 金融科技客戶的角度來討論雲上雲下混合部署的情況下如何利用亞馬遜雲科技雲原生服務、開源社區產品以及第三方工具構建無伺服器數據倉庫的解耦方法。 Apache EMR(E ...
  • 問題:Jetpack Compose 中使用 Material 包中的控制項,點擊預設會有水波紋效果。如何去除這個點擊水波紋效果呢? 看下 Modifier.clickable 的簽名: fun Modifier.clickable( interactionSource: MutableInterac ...
  • 看問題本質,設置全面屏,是系統視窗的行為,與 View 和 Compose 有什麼關係呢? 所以,原理和傳統 View 視圖是一樣的,甚至 Api 都是一模一樣的,不熟悉的可以看我之前的文章。傳送門: Android 全面屏體驗 那為什麼還要寫這篇文章呢?主要是在 Compose 中寫法上的一些區別 ...
  • 目錄一、低級別動畫 API1.1 animate*AsState1.2 Animatable1.3 Transition 動畫1.3.1 updateTransition1.3.2 createChildTransition1.3.3 封裝並復用 Transition 動畫1.4 remeberIn ...
  • 前言 鍵鼠事件是指在電腦操作中,用戶通過鍵盤和滑鼠來與電腦進行交互的行為。常見的鍵鼠事件包括按下鍵盤上的鍵、移動滑鼠、點擊滑鼠左鍵或右鍵等等。鍵鼠事件可以觸發許多不同的操作,比如在文本編輯器中輸入文字、在游戲中移動角色、在網頁上點擊鏈接等等。電腦操作系統和應用程式可以通過監聽鍵鼠事件來響應 ...
  • 前言 觸屏事件是指通過觸摸屏幕來進行操作和交互的事件。常見的觸屏事件包括點擊(tap)、雙擊(double tap)、長按(long press)、滑動(swipe)、拖動(drag)等。觸屏事件通常用於移動設備和平板電腦等具有觸摸屏幕的設備上,用戶可以通過觸摸屏幕上的不同區域或者以不同的方式進 ...
一周排行
    -Advertisement-
    Play Games
  • 基於.NET Framework 4.8 開發的深度學習模型部署測試平臺,提供了YOLO框架的主流系列模型,包括YOLOv8~v9,以及其系列下的Det、Seg、Pose、Obb、Cls等應用場景,同時支持圖像與視頻檢測。模型部署引擎使用的是OpenVINO™、TensorRT、ONNX runti... ...
  • 十年沉澱,重啟開發之路 十年前,我沉浸在開發的海洋中,每日與代碼為伍,與演算法共舞。那時的我,滿懷激情,對技術的追求近乎狂熱。然而,隨著歲月的流逝,生活的忙碌逐漸占據了我的大部分時間,讓我無暇顧及技術的沉澱與積累。 十年間,我經歷了職業生涯的起伏和變遷。從初出茅廬的菜鳥到逐漸嶄露頭角的開發者,我見證了 ...
  • C# 是一種簡單、現代、面向對象和類型安全的編程語言。.NET 是由 Microsoft 創建的開發平臺,平臺包含了語言規範、工具、運行,支持開發各種應用,如Web、移動、桌面等。.NET框架有多個實現,如.NET Framework、.NET Core(及後續的.NET 5+版本),以及社區版本M... ...
  • 前言 本文介紹瞭如何使用三菱提供的MX Component插件實現對三菱PLC軟元件數據的讀寫,記錄了使用電腦模擬,模擬PLC,直至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1. PLC開發編程環境GX Works2,GX Works2下載鏈接 https:// ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • 1、jQuery介紹 jQuery是什麼 jQuery是一個快速、簡潔的JavaScript框架,是繼Prototype之後又一個優秀的JavaScript代碼庫(或JavaScript框架)。jQuery設計的宗旨是“write Less,Do More”,即倡導寫更少的代碼,做更多的事情。它封裝 ...
  • 前言 之前的文章把js引擎(aardio封裝庫) 微軟開源的js引擎(ChakraCore))寫好了,這篇文章整點js代碼來測一下bug。測試網站:https://fanyi.youdao.com/index.html#/ 逆向思路 逆向思路可以看有道翻譯js逆向(MD5加密,AES加密)附完整源碼 ...
  • 引言 現代的操作系統(Windows,Linux,Mac OS)等都可以同時打開多個軟體(任務),這些軟體在我們的感知上是同時運行的,例如我們可以一邊瀏覽網頁,一邊聽音樂。而CPU執行代碼同一時間只能執行一條,但即使我們的電腦是單核CPU也可以同時運行多個任務,如下圖所示,這是因為我們的 CPU 的 ...
  • 掌握使用Python進行文本英文統計的基本方法,並瞭解如何進一步優化和擴展這些方法,以應對更複雜的文本分析任務。 ...
  • 背景 Redis多數據源常見的場景: 分區數據處理:當數據量增長時,單個Redis實例可能無法處理所有的數據。通過使用多個Redis數據源,可以將數據分區存儲在不同的實例中,使得數據處理更加高效。 多租戶應用程式:對於多租戶應用程式,每個租戶可以擁有自己的Redis數據源,以確保數據隔離和安全性。 ...