探索 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 MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...