簡介
常用縮寫詞
ASCII:美國信息交換標准碼
DOM:文檔對象模型
DTD:文檔類型定義
Html:超文本標記語言
W3C:萬維網聯盟
XHtml:可擴展超文本標記語言
XML:可擴展標記語言
XML 是一種受到良好支持的 Internet 標准,用於以一種特殊方式編碼結構化數據:XML 編碼的數據幾乎能夠用所有編程語言輕松解碼,甚至可以使用標准文本編輯器由人類閱讀或編寫。許多應用程序,特別是遵循現代標准的 Web 浏覽器,都可以直接處理 XML 數據。
XML 中的實體用於表示特殊字符(通常難以或不可能在標准鍵盤上輸入),重用 XML 代碼段,將文檔組織為幾個文件,以及簡化 DTD 的編寫。
什麼是實體?
實體是對數據的引用;根據實體種類的不同,XML 解析器將使用實體的替代文本或者外部文檔的內容來替代實體引用。本文中要介紹以下幾種實體,了解它們的工作方式,以及如何在我們自己的 XML 文檔中利用它們的優勢。
字符實體
命名實體
外部實體
參數實體
所有實體(除參數實體外)都以一個與字符(&)開始,以一個分號(;)結束。XML 標准定義了所有 XML 解析器都必須實現的 5 種標准實體,盡管它們還支持其他實體。
' 是一個撇號:'
& 是一個與字符:&
" 是一個引號:"
< 是一個小於號:<
> 是一個大於號:>
我們經常會在 XHtml 和 XML 文檔中看到和用到 &、< 和 > 實體,特別是那些通過展示示例來歸檔標記的文檔。
字符實體
對於字符實體,我們可以用十進制格式(&#nnn;,其中 nnn 是字符的十進制值)或十六進制格式(&#xhhh;,其中 hhh 是字符的十六進制值)來指定任意 Unicode 字符。
例如,大寫字母 A 是 Unicode 字符 U+0065。如果想將其表示為一個字符實體,可以輸入 A(十進制值)或 A(十六進制值)。另一個更有用的字符也許是 © —— 版權符號。這個版權符號的字符實體是 © 或 ©,因為它是 Unicode 字符 U+0169。
在進行其他實體相關的解析之前,將首先替代字符實體。對 XML 解析器而言,字符實體與直接輸入指定字符的效果完全相同。字符實體類似於 C 編程語言中的符(trigraphs):只是特定字符的替代表示。
還應該注意到,盡管 XML 解析器可以毫不費力地處理 “任何” 字符實體,但這些字符實體可能對處理應用程序和顯示系統毫無益處。確保能夠訪問適當的字體和編碼支持系統,以便在文檔中顯示任何稀奇古怪的字符。當前字體中找不到某個適當的字符時,多數系統會顯示一個某種占位符。
命名實體
命名實體(在 XML 規范中也稱為內部實體)就是我們在談論 “實體” 時所指的實體。命名實體在 DTD 或內部子集(即文檔中 <!DOCTYPE> 語句的一部分)中聲明,在文檔中用作引用。在 XML 文檔解析過程中,實體引用將由它的表示替代。
簡單來說,實體就是宏,它們在我們處理文檔時得到擴展。
XHTML 規范使用命名實體來表示 ISO 8859-1 (Latin 1) 字符集中包含的、但在多數鍵盤上沒有的特殊字符。其他實體用於指定特殊字符和符號。這些標准實體受到 Web 浏覽器的良好支持,甚至允許我們在只支持 7 位 ASCII 字符集的系統(是的,還有人在使用古老的大型機系統)上使用純文本編輯器來編寫 XHTML 文檔。清單 1 提供了 XHtml 1.0 的特殊字符的簡要列表。
清單 1. XHtml 1.0 的幾個特殊字符
<!ENTITY ndash "–"> <!-- en dash, U+2013 ISOpub -->
<!ENTITY mdash "—"> <!-- em dash, U+2014 ISOpub -->
<!ENTITY lsquo "‘"> <!-- left single quotation mark,
U+2018 ISOnum -->
<!ENTITY rsquo "’"> <!-- right single quotation mark,
U+2019 ISOnum -->
<!ENTITY sbquo "‚"> <!-- single low-9 quotation mark,
U+201A NEW -->
<!ENTITY ldquo "amp;“"> <!-- left double quotation mark,
U+201C ISOnum -->
<!ENTITY rdquo "”"> <!-- right double quotation mark,
U+201D ISOnum -->
如 清單 1(它是一塊 XHtml 1.0 Special Characters 聲明)所示,命名實體由字符實體替代。如 上一小節 所述,字符實體等同於在文檔中直接輸入的引用字符。
我們在文檔中使用 – 時,它由 Unicode 字符 U+2013(短橫線 - 字符)替代。由於 – 的替代文本是一個字符引用,因此它等同於輸入一個短橫線字符。
命名實體在整個文檔被讀取後進行解析。這樣,一些命名實體完全可以引用其他命名實體,其原因是所有實體都將在它們被擴展之前聲明。例如,清單 2 展示了兩個實體,其中一個實體引用另一個實體。
清單 2. 引用實體的實體
<!ENTITY c "Chris">
<!ENTITY ch "&c; Herborth">
在一個文檔中使用 &c; 將擴展為 Chris,&ch; 將擴展為完整的 Chris Herborth。
循環引用是實體中的錯誤。因創建了循環引用而使文檔無效時,解析器會報告錯誤。
使用 Firefox、Safari 和 Chrome 時,這些實體引用的效果與在存儲為 XML 文件的 XHtml 文檔中的效果一樣,但使用 Microsoft® Internet Explorer® 8 時效果不一樣。我將在 在文檔中定義實體 小節中介紹如何聲明命名實體。
外部實體
外部實體表示外部文件的內容。外部實體在有些情況下很有用,比如說,您在創建一本圖書並且想將每一章存儲為一個單獨的文件。您可能會創建一組如 清單 3 所示的實體。
清單 3. 外部實體引用其他文件
<!ENTITY chap1 SYSTEM "chapter-1.XML">
<!ENTITY chap2 SYSTEM "chapter-2.XML">
<!ENTITY chap3 SYSTEM "chapter-3.XML">
現在,當您在主圖書 XML 文件(參見 清單 4)中將這些實體放到一起時,這些文件的內容將插入在引用點。
清單 4. 將各章放到一起
<?XML version="1.0" encoding="utf-8"?>
<!-- Pull in the chapter content: -->
&chap1;
&chap2;
&chap3;
由於這些文件的內容被插入到 XML 文檔中,因此它們也必須是有效的 XML,而且它們必須是平衡的。也就是說,在一個外部實體的引用文件中開始的任何元素也必須在那個文件中結束。當 清單 4 中的 XML 文檔被解析時,它將被讀取為一個大文檔,包含 chapter-1.xml、chapter-2.xml 和 chapter-3.xml 文件的內容;XML 處理應用程序並不介意文檔寫入到 4 個單獨的文件中。
參數實體
參數實體只用於 DTD 和文檔的內部子集中。它們使用百分號(%)而不是與字符,可以是命名實體或外部實體。
在 XHTML DTD 中,參數實體用於引用在外部文件中聲明的 Latin 1, Special Characters and Symbols 實體集,以及用作快捷方式以重用 DTD 的某些部分,比如每個 XHtml 元素都支持的標准屬性集(參見 清單 5)。
清單 5. XHtml 1 DTD 中的一個參數實體
<!ENTITY % attrs "%coreattrs; %i18n; %events;">
<!ENTITY % coreattrs
"id ID #IMPLIED
class CDATA #IMPLIED
style %StyleSheet; #IMPLIED
title %Text; #IMPLIED"
>
<!ENTITY % i18n
"lang %LanguageCode; #IMPLIED
XML:lang %LanguageCode; #IMPLIED
dir (ltr|rtl) #IMPLIED"
>
如 清單 5 所示,參數實體可以引用其他參數實體。與命名實體一樣,參數實體在整個文檔被讀取之後才被擴展。
在文檔中定義實體
您也許已經注意到,實體使用 ENTITY 聲明進行定義,既可以作為外部 DTD 的一部分(參見 清單 6),也可以作為文檔的外部子集的一部分(參見 清單 7)。
清單 6. DTD 中的實體聲明
<!-- 6.1 Named entity for site name: -->
<!ENTITY dw "developerWorks">
<!-- 6.2 External entity for re-use: -->
<!ENTITY bio SYSTEM "dw-author-bio.XML">
<!-- 6.3 Parameter entity for use in DTD -->
<!ENTITY % English "en-US|en-CA|en-UK">
在聲明命名實體時,指定實體的名稱及其替代文本。替代文本可以包含字符實體、命名實體和元素等,但不包含參數實體。
清單 7. 內部子集中的實體聲明
<?XML version="1.0" encoding="UTF-8"?>
<!DOCTYPE Html
PUBLIC "-//W3C//DTD XHtml 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xHtml1-strict.dtd"
[
<!ENTITY test-entity "This <em>is</em> an entity.">
]>
<html XMLns="http://www.w3.org/1999/xHtml">
<head>
<meta http-equiv="Content-Type" content="application/xHtml+XML;charset=utf-8"/>
<title>EntitIEs in XML</title>
</head>
<body>
<h1>EntitIEs in XML</h1>
<p>&test-entity;</p>
<p>You can use it anywhere you'd use a standard XHtml entity:</p>
<pre>&test-entity;</pre>
</body>
</Html>
清單 7 中的 XHtml 文檔(在我的系統上保存為 entitIEs.XML)在其內部子集中聲明了一個名為 test-entity 的新實體。內部子集是 <!DOCTYPE> 聲明的一部分,位於 DTD 的 PUBLIC 和/或 SYSTEM 標識符之後的方括號中。
浏覽器目前似乎不支持內部子集中的外部實體或參數實體,這也許是一個安全措施。當這兩種類型的實體與 Web 浏覽器的呈現引擎一起使用時,可能被用於創建拒絕服務攻擊或其他惡意文檔。
在文檔中使用實體
現在已經熟悉在文檔中使用實體的機制;DTD 中的參數實體的工作方式與此相同。前面所示的清單展示了如何使用各種實體:
字符實體 — 清單 1
命名實體 — 清單 2 和 清單 7
外部實體 — 在 清單 3 中聲明,在 清單 4 中使用
參數實體 — 清單 5
在需要反復輸入相同的文本時,可以嘗試利用實體。以下是一些不錯的實體示例:公司的正式名稱、正在進行文檔記錄的產品的名稱、版權、商標、注冊商標通知,以及電子郵件地址(參見 清單 8)。
清單 8. 通過實體減少輸入
<!ENTITY co "Father Karass' Olde Tyme Steambots, LLC">
<!ENTITY prod "Semi-Autonomous Security Servant (SASSbot)">
<!ENTITY c "Copyright © 2010 &co; All Rights Reserved.">
<!ENTITY author "Chris Herborth (chrish@pobox.com)">
可能變化的事物(比如產品名稱)非常適合使用實體,這與在程序源代碼中聲明常量很相似。當產品名稱變化時,我們只需更新實體聲明,不必搜索並替代所有文件(參見 清單 9)。
清單 9. 使用實體輕松更新不斷變化的文檔
<!-- Current name: -->
<!ENTITY prod "Semi-Autonomous Security Servant (SASSbot)">
<!-- Old names preserved for posterity: -->
<!-- Original R&D name: -->
<!--ENTITY prod "Security Bot"-->
<!-- Marketing name v1 -->
<!--ENTITY prod "Security Servant Bot"-->
<!-- Marketing name v2 -->
<!--ENTITY prod "Autonomous Security Servant Bot"-->
結束語
基於 XML 的標准(比如 XHtml)定義了一個有用的實體庫,這使得創建包含不能在標准鍵盤上直接輸入的字符的文檔成為可能。命名實體的作用類似於宏,允許您使用實體引用替代重復或難以輸入的文本。盡管 Web 浏覽器不支持外部實體,但是我們可以通過其他 XML 應用程序來使用它們創建復合文檔,這使得標准化和重用文檔的某些部分變得更容易。參數實體用於將外部聲明拖到 DTD 中,或者用於創建 DTD 內部宏來改善可讀性。
在 XML 文檔的 DOCTYPE 聲明中聲明命名實體很簡單,而且您可能已經知道如何在文檔主體中使用它們。