XML學習筆記(DTD約束)

1. XML語法

在說明DTD約束前,先介紹XML的基本語法:
文檔聲明

<? 版本信息[編碼信息][文檔獨立信息]?>
例:<?xml version="1.0" encoding="utf-8" standalone="yes"?>

元素定義:
由開始標記、屬性、元素內容、結束標記構成

例:<城市>清遠</城市>

屬性定義:
一個個元素中可以有多個屬性

例:<售價 單位="元">68</售價>

註釋:<!-- 這裏寫註釋內容 -->

DTD約束

DTD約束是早期出現的一種XML約束模式語言,根據它的語法創建出來的文件稱爲DTD文件。

DTD的引入方式:

外部式:

  1. <!DOCTYPE 根元素名稱 SYSTEM “外部DTD文件的URL”>
  2. <!DOCTYPE 根元素名稱 PUBLIC “DTD名稱” “外部DTD文件的URL”>

用一個例子來解釋如何使用外部式引入DTD

book.dtd文件
<!ELEMENT 書架 (書+)>
<!ELEMENT 書 (書名,作者,售價)>
<!ELEMENT 書名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售價 (#PCDATA)>
book.xml文件
<?xml version="1.0" encoding="utf-8"?>
<!-- 這裏引入book.dtd對book.xml進行約束 -->
<!DOCTYPE 書架 SYSTEM "book.dtd">
<書架>
    <書>
        <書名>***</書名>
        <作者>***</作者>
        <售價>10</售價>
    </書>
    <書>
        <書名>****</書名>
        <作者>****</作者>
        <售價>100</售價>
    </書>
</書架>

內嵌式:直接將DTD約束寫在XML文檔中

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE 書架 [
    <!ELEMENT 書架 (書+)>
    <!ELEMENT 書 (書名,作者,售價)>
    <!ELEMENT 書名 (#PCDATA)>
    <!ELEMENT 作者 (#PCDATA)>
    <!ELEMENT 售價 (#PCDATA)>
]>
<書架>
    <書>
        <書名>***</書名>
        <作者>***</作者>
        <售價>10</售價>
    </書>
    <書>
        <書名>****</書名>
        <作者>****</作者>
        <售價>100</售價>
    </書>
</書架>

DTD語法

DTD的結構一般由元素類型定義、屬性定義、實體定義、記號定義等構成

  1. 元素定義:每一條<!ELEMENT ...>語句定義一個元素
<!ELEMENT 元素名稱 元素內容>

       在上面定義格式中,元素名稱是自定義的;元素內容是對元素包含內容的聲明,包括數據類型和符號兩部分,它共有5中形式:

  • #PCDATA:表示元素中嵌套的內容是普通字符串,其中,關鍵字PCDATA是ParsedCharacter Data的簡寫。例如,<!ELEMENT 書名 (#PCDATA)> 表示書名所嵌套的內容是字符串類型。
  • 子元素:說明元素包含的元素。例如:<!ELEMENT 書 (書名,作者,售價)>表示書中要嵌套書名、作者、售價等子元素
  • 混合內容:表示元素既可以包含字符數據,也可以包含子元素。混合數據必須被定義零個或多個,例如:<!ELEMENT 書 (#PCDATA書名) *>表示書中嵌套的子元素書名包含零個或多個,並且書名是字符串文本格式。
  • EMPTY:該元素是一個空元素。使用場景:元素在文檔中已經表明了明確含義,就可以在DTD中用關鍵字 EMPTY 表明空元素。例如:<!ELEMENT br EMPTY>,br是一個沒有內容的空元素。
  • ANY:表示元素可以包含任何的字符數據和子元素。例如:<!ELEMENT 聯繫人 ANY>表示聯繫人可以包含任何形式的內容。但是在實際開發中,應該儘量避免使用ANY,因爲除了根元素外,其他使用ANY的元素都將失去DTD對XML文檔的約束效果。

       在定義元素時,元素內容中可以包含一些符號,不同的符號具有不同的作用。具體如下:

  • 問號[?]:表示該對象可以出現0次或1次
  • 星號[*]:表示該對象可以出現0次或多次
  • 加號[+]:表示該對象可以出現1次或多次
  • 豎線[|]:表示在列出的對象中選擇1個
  • 逗號[,]:表示對象必須按照指定的順序出現
  • 括號[()]:用於給元素進行分組
  1. 屬性定義:基本語法格式如下
<!ATTLIST 元素名
    屬性名1 屬性類型 設置說明
    屬性名2 屬性類型 設置說明
    ......
>

       在上面屬性定義的語法格式中,”元素名“是屬性所屬元素的名字,”屬性名“是屬性的名稱,”屬性類型“則用來指定該屬性屬於那種類型,”設置說明“用來說明該屬性是否必須出現。關於”屬性類型“和”設置說明“的相關講解如下:
2.1. 設置說明:定義元素的屬性時,有4中設置說明可以選擇

設置說明 含義
#REQUIRED 表示元素的該屬性是必須的,例如,當定義聯繫人信息的DTD時,我們希望每一個聯繫人都有一個聯繫電話屬性,這時,可以在屬性聲明時使用REQUIRED
#IMPLED 表示元素可以包含該屬性,也可以不包含該屬性。例如,當定義一本書的信息時,發現書的頁數屬性對讀者無關緊要,這時,在屬性聲明時可以使用IMPLIED
#FIXED 表示一個固定的屬性默認值,在XML文檔中不能將該屬性設置爲其他值。使用#FIXED關鍵字時,還需要爲該屬性提供一個默認值。當XML文檔中沒有定義該屬性時,其值將被自動設置爲DTD中定義的默認值
默認值 和FIXED一樣,如果元素不包含該屬性,該屬性將被自動設置爲DTD中定義的默認值。不同的是,該屬性的值是可以改變的,如果XML文件中設置了該屬性,新的屬性值會覆蓋DTD中定義的默認值

2.2. 屬性類型:在DTD中定義元素的屬性時,有10種屬性類型可以選擇,常見的幾種屬性類型如下

  • CDATA
           這是最常用的一種屬性類型,表明屬性類型是字符數據,與元素內容說明種的#PCDATA相同。當然,在屬性設置值中出現的特殊字符,也需要使用轉義字符序列來表示,例如,用”&“表示字符”&“,用”&lt“表示字符”<“等。
  • Enumerated(枚舉類型)
           在聲明屬性時,可以限制屬性的取值只能從一個列表中選擇,這類屬性屬於Enumerated(枚舉類型)。需要注意的是,在DTD定義中並不會出現關鍵字Enumerated。案例enum.xml展示如何定義Enumerated類型的屬性。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- 內嵌式DTD約束 -->
<!DOCTYPE 購物籃 [
    <!ELEMENT 購物籃 ANY>
    <!-- EMPTY表示肉及不包含字符數據,也不包含子元素,是一個空元素 -->
    <!ELEMENT 肉 EMPTY>
    <!ELEMENT 肉 品種 (雞肉|牛肉|豬肉|魚肉) "雞肉">
]>
<購物籃>
    <肉 品種="魚肉"/>
    <肉 品種="牛肉"/>
    <肉/>
</購物籃>

       在enum.xml中,“品種”屬性的類型是Enumerated,其值只能是“雞肉、牛肉、豬肉、魚肉”,而不能使用其他值。“品種”屬性的默認值是“雞肉”,所以,即使<購物籃>元素中的第三個子元素沒有顯示定義“品種”這個屬性,但它實際上也具有“品種”這個屬性,且屬性的取值爲“雞肉”。

  • ID
           一個ID類型的屬性用於唯一標識XML文檔中的一個元素。其屬性值必須遵守XML名稱定義的規則。一個元素只能有一個ID類型的屬性,而且ID類型的屬性必須設置爲#IMPLIED或#REQUIRED。因爲ID類型屬性的每一個取值都是用來標識一個特定元素,所以,爲ID類型的屬性提供默認值,特別是固定的默認值是毫無意義的。
<!-- 例:id.xml -->
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!ELEMENT 聯繫人列表 [
    <!ELEMENT 聯繫人列表 ANY>
    <!ELEMENT 聯繫人 (姓名,EMAIL)>
    <!ELEMENT 姓名 (#PCDATA)>
    <!ELEMENT EMAIL (#PCDATA)>
    <!ELEMENT 聯繫人 編號 ID #REQUIRED>
]>
<聯繫人列表>
    <聯繫人 編號="id1">
        <姓名>張三</姓名>
        <EMAIL>[email protected]</EMAIL>
    </聯繫人>
    <聯繫人 編號="id2">
        <姓名>李四</姓名>
        <EMAIL>[email protected]</EMAIL>
    </聯繫人>
</聯繫人列表>

       在 id.xml 中,將元素爲<聯繫人>的編號屬性設置爲#REQUIRED,說明每個聯繫人都有一個編號,同時,屬性編號的類型爲ID,說明編號是唯一的。這樣一來,通過編號就可以找到唯一對應的聯繫人了。

  • IDREF和IDREFS
           在上面的 id.xml 中,雖然張三和李四兩個聯繫人的ID編號是唯一的,但是這兩個ID類型的屬性沒有發揮作用,這時可以使用IDREF類型,使這兩個聯繫人之間建立一種一對一的關係。案例 Idref.xml 展示IDREF的使用:
<!-- 例:Idref.xml 演示如何使用IDREF -->
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE 聯繫人列表 [
    <!ELEMENT 聯繫人列表 ANY>
    <!ELEMENT 聯繫人 (姓名,EMAIL)>
    <!ELEMENT 姓名 (#PCDATA)>
    <!ELEMENT EMAIL (#PCDATA)>
    <!ELEMENT 聯繫人
              編號 ID #REQUIRED
              上司 IDREF #IMPLIED
    >
]>
<聯繫人列表>
    <聯繫人 編號="id1">
        <姓名>張三</姓名>
        <EMAIL>[email protected]</EMAIL>
    </聯繫人>
    <聯繫人 編號="id2" 上司="id1">
        <姓名>李四</姓名>
        <EMAIL>[email protected]</EMAIL>
    </聯繫人>
</聯繫人列表>

       在 Idref.xml 中,爲元素<聯繫人列表>的子元素<聯繫人>增加一個名稱爲上司的屬性,並且將該屬性的類型設置爲IDREF,IDREF類型屬性的值必須爲一個已經存在的ID類型的屬性值。在第二個<聯繫人>元素中,將“上司”屬性設置爲第一個聯繫人的編號的屬性值,如此一來,就可以形成兩個聯繫人元素之間的對應關係,即李四的上司是張三。
       IDREF可以是兩個元素之間形成一對一的關係,而IDREFS可以是元素之間形成一對多的關係。例如:學生借書(Library.xml)

<!-- Library.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE library [
    <!ELEMENT library (books,records)>
    <!ELEMENT books (book+)>
    <!ELEMENT book (title)>
    <!ELEMENT title (#PCDATA)>
    <!ELEMENT records (item+)>
    <!ELEMENT item (data,person)>
    <!ELEMENT data (#PCDATA)>
    <!ELEMENT person EMPTY>
    <!ATTLIST book bookid ID #REQUIRED>
    <!ATTLIST person name CDATA #REQUIRED>
    <!ATTLIST person borrowed IDREFS #REQUIRED>
]>
<library>
    <books>
        <book bookid="b0101">
            <title>xml基礎</title>
        </book>
        <book bookid="b0102">
            <title>xml進階</title>
        </book>
        <book bookid="b0103">
            <title>xml再進階</title>
        </book>
    </books>
    <records>
        <item>
            <data>2019-12-26</data>
            <person name="李四" borrowed="b0101 b0102"/>
        </item>
        <item>
            <data>2019-12-27</data>
            <person name="李四" borrowed="b0101 b0102 b0103"/>
        </item>
    </records>
</library>

       除了上述的幾種屬性類型外,DTD約束中還有NMTOKEN、NMTOKENS、NOTITION、ENTITY和ENTITYS幾種屬性類型。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章