第2章 XML文档类型定义
本章目标
■ 了解DTD的作用
■ 掌握内部DTD的使用
■ 掌握外部DTD的使用
■ 掌握DTD的文档结构
■ 掌握DTD中不同类型元素的定义及使用
■ 掌握DTD中各种属性的定义及使用
■ 掌握DTD中实体的定义及使用
学习导航
任务描述
【描述2.D.1】
创建并使用内部DTD规范XML文档。
【描述2.D.2】
创建并使用外部DTD规范XML文档。
【描述2.D.3】
创建并使用带属性的DTD,演示CDATA的使用。
【描述2.D.4】
创建并使用带NMTOKEN属性的DTD,演示NMTOKEN的使用。
【描述2.D.5】
创建并使用带ID属性的DTD,演示ID的使用。
【描述2.D.6】
创建并使用带IDREF(IDREFS)属性的DTD,演示IDREF的使用。
【描述2.D.7】
创建并使用带枚举类型属性的内部DTD,演示枚举类型的使用。
【描述2.D.8】
创建并使用带自定义实体的内部DTD,演示自定义实体的使用。
2.1 DTD概述
XML的精髓在于“无障碍”数据交换和数据共享,编写格式良好的XML文档,使其他用户能够理解符合我们创建的XML词汇表(包括元素及属性等)的文档结构,须通过某种通用的方式说明词汇表的语法规则。为此,XML1.0提供了一种机制——文档类型定义(Document Type Definition,DTD),并将其作为规范的一部分。DTD使用正式的语法定义XML文档的结构和允许值。
2.1.1 DTD简介
XML的最大灵活性在于允许用户制定基于信息描述、体现数据之间逻辑关系的自定义标记,确保文档具有较强的易读性、清晰的语义和易检索性。因此,一个完全意义上的XML文档不仅仅是“Well Formed”(格式良好的),而且还应该是使用了一些自定义标记的“Validating XML”(有效的)文档,即它必须遵守文档类型定义DTD中已声明的各种规定。文档类型定义DTD,用来描述XML文档的结构。DTD定义了XML文档中可用的合法元素,并且定义了可以在文档中存在的元素、元素可以具有的属性、元素的层次结构,以及元素在整个文档中出现的顺序。简而言之,DTD规定了一个语法分析器以解释一个“Validating XML”文档所需要知道的所有规则的细节。
DTD可以看做是一个或多个XML文件的模板,这些XML文件中的元素、元素的属性、元素的排列方式/顺序、元素能够包含的内容等,都必须符合DTD中的定义。XML文件中的元素(标记)是根据应用的实际情况来创建的。想要创建一份完整性高、适应性广的DTD是非常困难的,因为各行各业都有他们自己的行业特点,所以DTD通常是以某种应用领域为定义的范围,如:生产、医学、工商、金融。DTD定义的元素涵盖范围越广泛,它就越复杂。
引入DTD的优势如下所示。
引入DTD,每个XML文件可以携带一个自身格式的描述。
■ 引入DTD,不同组织的人可以使用一个通用DTD交换数据,应用程序可以使用一个标准DTD校验从外部世界接收来的XML数据是否有效。
■ 引入DTD,便于在网络上进行数据的共享和交互。例如,两个相同行业不同地区的人使用同一个DTD文件作为文档的创建规范,那么他们的数据就很容易交换和共享。网络上其他用户补充的数据,只需要根据公用的DTD规范来建立即可。
目前,针对不同的行业和应用,已经有数量众多的写好的DTD文件可以利用,这些DTD文件已经建立了通用的元素和标签规则。用户无须重新创建,只要在这些DTD文件的基础上加入特定的新元素即可。当然,用户也可以创建自己的DTD。
2.1.2 DTD声明
DTD是与XML文档相关的。通常,XML文档中通过DOCTYPE声明将XML与DTD建立关联的指令,当验证有效性的解析器读到该指令时,它获取相应的DTD,并根据其中定义的规则对文档进行校验。
DOCTYPE声明由以下部分组成:关键字、文档的根元素名称、可选的外部标记符,以及可选的标记声明块。外部标记符用于外部DTD(外部子集)的命名和定位,标记声明块是由标记声明(内部子集)构成的。
DOCTYPE声明语法示例如下:
<?xml version="1.0" standalone="no" encode="UTF-8"?> <!DOCTYPE Catalog ...> <Catalog >
第2行中使用“<!DOCTYPE>”标记,该标记就是DOCTYPE声明,说明该文档的第一个元素(根元素)是Catalog,省略号“…”隐藏了DOCTYPE声明的其余部分。
XML规范定义了两种DOCTYPE声明的方法。
内部DTD声明:在DOCTYPE声明体中直接定义内部标记子集。
■ 外部DTD声明:用户可以在独立的DTD文件中提供外部标记子集声明,再通过DOCTYPE声明将其引入。
这两种声明方式可以同时使用。
注意 DOCTYPE声明必须位于XML声明之后,且在任何文档元素之前。但是,XML声明和DOCTYPE声明之间可以插入注释和处理指令。
2.1.3 内部DTD
可以使用“<!DOCTYPE[.....]>”语句在XML文档序言部分声明DTD文档的定义,引入内部DTD的XML文档的语法结构如下:
<?xml version = "1.0" encoding="GB2312"?> <!DOCTYPE element-name[ 元素描述 ]> <!--文档数据区.......-->
其中:
<!DOCTYPE:表示开始设定DTD,注意DOCTYPE必须大写。
■ element-name:指定此DTD的根元素的名称,一个XML文件只能有一个根元素。注意,如果XML文档使用了DTD,那么文件中的根元素就在这里指定。
■ [ ]>:在[ ]标记里面定义XML文件中使用的元素,然后用“>”结束DTD的定义。
下述代码用于实现任务【描述2.D.1】,创建并使用内部DTD规范XML文档。
【描述2.D.1】 student_1.xml
1.<?xml version="1.0" encoding="GB2312"?> 2.<!DOCTYPE students [ 3.<!ELEMENT students (student)+> 4.<!ELEMENT student (name,age,tel)> 5.<!ELEMENT name (#PCDATA)> 6.<!ELEMENT age (#PCDATA)> 7.<!ELEMENT tel (#PCDATA)> 8.]> 9.<students> 10. <student> 11. <name>Tom</name> 12. <age>14</age> 13. <tel>88889999</tel> 14. </student> 15.</students>
上述文档是一个格式良好,并且有效(满足DTD校验)的XML文档,其中:
* 第1行代码是一个XML声明,表示文档遵循的是XML的1.0版的规范。
* 第2~8行即为内部DTD的定义内容。这个内部DTD中,定义了名为students的元素是XML文档中的根元素,此根元素拥有至少一个student子元素,子元素student有name、age和tel三个子元素。name、age和tel元素都为“#PCDATA”类型。
注意 在进行DTD书写时,特别注意元素定义时,需要在元素名称和内容之间加空格隔开,如:“<!ELEMENT students”和“(student)+>”之间要通过空格隔开。
2.1.4 外部DTD
外部DTD是一个独立于XML文档的文件,实际上也是一个文本文件,只是使用.dtd作为文件扩展名。外部DTD独立于XML文档,所以它可以供多个XML文件使用,就像用同一个模板可以写出多个不同内容的文件一样。
使用外部DTD的好处是:它可以方便高效地被多个XML文档所共享。只要写一个DTD文档,就可以被多个XML文档所引用。
除了没有内部DTD中的<!DOCTYPE [.....]>语句外,外部DTD的创建方式、语法和内部DTD是一样的。XML文档使用DTD文件的声明语句来引用创建好的外部DTD文件,此语句必须位于XML文档的文件序言区,并且要紧跟在XML声明语句后面,DTD文件的声明语句格式如下:
<!DOCTYPE type-of-doc SYSTEM/PUBLIC "dtd-name">
具体介绍如下所示。
* <!DOCTYPE:是指要定义一个DOCTYPE。
* type-of-doc:指定文档类型的名称,由用户自己定义,通常与使用这个DTD文件的XML文档的根元素名称一致。
* SYSTEM/PUBLIC:这两个参数只用其一。SYSTEM是指文档使用的是私有的外部DTD文件,这个关键字主要用于引用一个作者或组织所编写的众多XML文档中通用的DTD;而PUBLIC则指文档调用一个公用的外部DTD文件,此外部DTD文件经过了公开讨论,即一个由权威机构制定的、提供给特定行业或公众使用的DTD。
* dtd-name:是存放DTD文件的地址和名称。
综上所述,可以这样理解引入外部DTD的XML文档的结构,即:
< ?xml version = "1.0"?> <!DOCTYPE 根元素名 SYSTEM/PUBLIC "外部DTD文件名及其位置"> <!--文档数据区.......-->
下述代码用于实现任务【描述2.D.2】,创建并使用外部DTD规范XML文档。
定义外部DTD文档内容如下所示。
【描述2.D.2】 student_2.dtd
<?xml version="1.0" encoding="GB2312"?> <!ELEMENT students (student+)> <!ELEMENT student (name,age,tel*)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> <!ELEMENT tel (#PCDATA)>
关联外部DTD文件的XML的总体代码如下:
【描述2.D.2】 student_2.xml
<?xml version="1.0" encoding="GB2312"?> <!DOCTYPE students SYSTEM "student_2.dtd"> <students> <student> <name>Tom</name> <age>14</age> <tel>88889999</tel> </student> </students>
上述代码中,第2行代码的作用就是将外部DTD文件student_2.dtd应用于此XML文档。
2.2 DTD语法
DTD是保证XML文档有效性的方法之一,可使XML解析器通过比较XML文档和DTD文件来确定文档是否符合规范、元素和标签使用是否正确等。一个DTD文档包含:元素的定义规则、元素间关系的定义规则、元素可使用的属性以及可使用的实体或符号规则等。DTD文件也是一个ASCII的文本文件,后缀名为.dtd。
2.2.1 元素声明
元素是XML的核心与灵魂,它包含了实际的文档信息,并指出了这些信息的逻辑结构。元素以树形分层机构排列,可以嵌套在其他元素中。
在DTD中,元素类型是通过ELEMENT标记声明的。除了关键字,标记还提供所声明类型的名称和内容规范。正如第1章所述,元素类型名要遵守XML对名称的限制。名称可以是字母、数字,也可以使用标点符号,如:冒号(:)、下画线(_)、连字符(-)和句点(.)。然而,名称不能以数字开头。它的第一个字符只能是字母、下画线或冒号。
注意 虽然名称中可以使用冒号,但是鉴于后面即将介绍的命名空间,最好避免在元素名称中使用冒号。
DTD中使用元素类型声明ETD(Element Type Declaration)来声明所有有效的文档元素。其语法结构如下:
<!ELEMENT element-name element-definition>
具体介绍如下所示。
* <!ELEMENT:表示开始元素设置,注意此处ELEMENT关键字必须是大写。
* element-name:表示要设置的元素的名称。
* element-definition:指明要对此元素进行怎样的定义,就是说<元素>...</元素>之间能够包含什么内容,是其他元素还是一般性的文字。
XML中按元素的内容(element-definition)可以将元素划分为五类,不同类型的元素使用DTD进行定义时的语法如下。
1.ANY类型
如果不需要对元素的内容进行限制,可以在DTD中使用ANY元素类型。定义方式为:
<!ELEMENT element-name ANY>
XML文档里该元素中可以包含任何在DTD中定义的元素内容。建议一般只把文档的根元素规定为ANY类型。将根元素设为ANY类型后,元素出现的次数和顺序不受限制。
注意 为了增强可读性,每个元素定义通常占据单独的一行。
2.EMPTY类型
EMPTY元素类型。定义方式为:
<!ELEMENT element-name EMPTY>
这类元素在XML文档中使用空元素标记,即元素中没有内容,不能包含子元素和文本,但可以有属性。例如,对于下面的DTD定义:
<!ELEMENT student EMPTY>
以下这个元素是合法的:
<student name="Jack" age="16"/>
而下面这些元素的定义就是非法的,因为此元素应该为空元素,既不能有内容也不能有子元素:
<student>Jack</student> <student><name>Jack</name></student>
3.#PCDATA类型
#PCDATA类型的元素(纯文本元素,或称简单元素)可以包含任何字符数据,但是不能在其中包含任何子元素。PCDATA代表字符数据,为防止与关键字混淆,需加“#”前缀。其定义方式为:
<!ELEMENT element-name (#PCDATA)>
下面的DTD定义说明name只能包含字符数据,即非标记文本,并且它不能包含自己的子元素:
<!ELEMENT name (#PCDATA)>
下面这些元素定义都是合法的:
<name>Jack</name> <name>2008</name> <name>123.456</name>
因为XML不会去检查PCDATA的内容,只要是文本就可以。但下面的元素定义是非法的:
<name> <firstname>White</firstname> <lastname>Smith</lastname> </name>
4.父元素类型
父元素类型只能包含子元素,并且这些子元素外没有文本。这类元素在DTD中通过正则表达式规定子元素出现的顺序和次数。语法分析器将这些正则表达式与XML文档内部的数据模式相匹配,从而判断该文档是否是有效的XML。表2-1列出了在DTD中用到的正则表达式的元组运算符。
表2-1 正则表达式的元组运算符
表2-2通过示例介绍了上述元组运算符的用法。
表2-2 用法示例
对于下述DTD定义:
<!ELEMENT students (student+)> <!ELEMENT student (name,age,tel*)>
表明:
students元素是父元素,它可以有至少一个student子元素(由“+”表示);student元素必须有一个name元素、一个age元素、零个或多个tel元素(由“*”表示),而且name、age、tel出现的次序必须一致。
5.混合元素类型
混合元素类型是包含子元素和文本数据的混合体,混合元素的定义方式为:
<!ELEMENT 元素名 (#PCDATA | element-name1 | element-name2 | ……)*>
对于下述DTD定义就是一个混合元素:
<!ELEMENT students (#PCDATA|student)*>
在DTD定义中,带有字符数据的混合元素只能指定可出现的子元素的名称,而不能限定它们出现的顺序及每个元素的出现次数,或者它们是否出现,严重地限制文档的结构。因此,最好避免使用混合元素。
注意 混合元素在声明时,其语法结构中除了可以改变子元素数目以外,其他的任何改动都是不合法的。也就是说,不能在包括“#PCDATA”的元素声明中使用逗号、问号或加号;用竖线分隔的元素和“#PCDATA”的列表是合法的。其他用法是不合法的。
2.2.2 属性声明
属性是对元素的补充和修饰,它能够将一些简单的特性与元素相关联。通过属性,可以给元素绑定大量信息。例如,在HTML标记IMG中,SRC就是一个属性。属性在DTD中是使用ATTLIST标记声明的。对于含属性的元素,至少要通过一个ATTLIST标记声明其属性列表。ATTLIST声明由以下部分构成:ATTLIST关键字、属性修饰的元素名称,以及零个或多个属性定义。属性的定义方式为:
<!ATTLIST 元素名 属性名称 属性类型 取值方式 >
实际运用中,一个元素往往不只有一个属性,当需要为一个元素定义多个属性时,也可采用如下定义方式:
<!ATTLIST 元素名 属性名称 属性类型 取值方式 属性名称 属性类型 取值方式 ... >
其中,属性取值方式如表2-3所示。
表2-3 属性取值方式
属性类型用来指定该属性的取值类型,DTD的属性类型如表2-4所示。
表2-4 属性类型
下面通过实例,对常用的属性类型及属性取值方式进行详细介绍。
1.CDATA
声明为CDATA的属性值可以是任何文本串(包括数字和中文),但不能包含“<”,“&”,“"”等字符串,对于下述属性声明:
<!ATTLIST student name CDATA #REQUIRED>
在XML文档中,下列写法都是合法有效的:
<student name="Jack"/> <student name="杰克"/> <student name="123456"/>
下述代码用于实现任务【描述2.D.3】,创建并使用带属性的内部DTD,演示CDATA的使用。
【描述2.D.3】 family.xml
<?xml version="1.0" encoding="GB2312"?> <!DOCTYPE family [ <!ELEMENT family (person+, appliance*)> <!ELEMENT person EMPTY> <!ELEMENT appliance EMPTY> <!ATTLIST person name CDATA #REQUIRED age CDATA #REQUIRED tel CDATA #IMPLIED > <!ATTLIST appliance name CDATA #REQUIRED quantity CDATA "1" comments CDATA #IMPLIED > ]> <family> <person name="Rose" age="25"/> <person name="杰克" age="28" tel="88887777"/> <appliance name="冰箱" quantity="2"/> </family>
上述代码中为person元素声明了三个属性:name、age和tel,其中tel可有可无,其他两个属性必须出现;为appliance声明了三个属性,comments可有可无,name和quantity是必须出现的,并且属性quantity声明默认值:1。上述XML文档合法有效。
如果将XML文档的XML数据部分写为如下形式:
<family> <person name="Rose" /> <!-- Error,缺少age属性--> <person name="杰克" age="28" tel="88887777"/> <appliance name="冰箱" color="red"/><!-- Error,未定义color属性--> </family>
将提示XML验证错误信息,原因是此XML数据部分声明未遵循其关联的DTD文档规范。
2.NMTOKEN/NMTOKENS
某些情况下,可能希望将属性值作为标记,代表某种特殊的意义,如:通过标记信息告知解析器对于此文件的处理级别、安全级别等。此时就需要XML中的NMTOKEN(name token,名称记号),NMTOKEN是CDATA的一个子集,表示属性值必须是英文字母、数字、句点、连字符、下画线或冒号组成,即满足XML名称规范。
注意 NMTOKEN与元素和属性名称并不完全相同,NMTOKEN的第一个字符可以是任意字符,但建议与XML名称规范一致,方便阅读。
下述代码用于实现任务【描述2.D.4】,创建并使用带NMTOKEN属性的内部DTD,演示NMTOKEN的使用。
【描述2.D.4】 NMTOKENdemo.xml
<?xml version="1.0" encoding="GB2312"?> <!DOCTYPE poems [ <!ELEMENT poems (poem*)> <!ELEMENT poem (title, content)> <!ATTLIST poem security_level NMTOKEN #REQUIRED> <!ELEMENT title (#PCDATA)> <!ELEMENT content (#PCDATA)> ]> <poems> <poem security_level="all"> <title >黄鹤楼</title> <content> 昔人已乘黄鹤去,此地空余黄鹤楼。黄鹤一去不复返,白云千载空悠悠。 晴川历历汉阳树,芳草萋萋鹦鹉洲。日暮乡关何处是?烟江波上使人愁。 </content> </poem> </poems>
上述代码表示元素poem有一个名为security_level的属性,其值符合XML名称规则。用户可以通过该属性来控制文档的访问。由于定义属性列表时使用了NMTOKEN,用户只需创建新值就能适应新的安全级别要求,而不必每次都编辑DTD。
NMTOKENS与NMTOKEN类似,是NMTOKEN的复数,每个NMTOKEN之间通过空格隔开。下述代码演示了NMTOKENS的使用:
<!ATTLIST poem security_level NMTOKENS #REQUIRED> <poem security_level="role1 role2 role5"> …… </poem>
在这里,该poem实例可以被role1、role2和role5访问。就类型而言,这些数据都是有效的NMTOKEN值。
注意 NMTOKENS的值与枚举类型不同,解析器不检查这些NMTOKENS取值的有效性,用户必须确保自己使用了适当的名称。
3.ID
ID类型的属性表明该属性的取值在整个文档中必须是唯一的。它可以作为元素的唯一标识符。每个元素至多有一个ID类型的属性。该ID必须以一个字母开头。
下述代码用于实现任务【描述2.D.5】,创建并使用带ID属性的内部DTD,演示ID的使用。
【描述2.D.5】 IDdemo.xml
<?xml version="1.0" encoding="GB2312"?> <!DOCTYPE poems [ <!ELEMENT poems (poem*)> <!ELEMENT poem (content)> <!ATTLIST poem NO ID #REQUIRED title CDATA #REQUIRED> <!ELEMENT content (#PCDATA)> ]> <poems> <poem NO="Z001" title="黄鹤楼"> <content> 昔人已乘黄鹤去,此地空余黄鹤楼。黄鹤一去不复返,白云千载空悠悠。 晴川历历汉阳树,芳草萋萋鹦鹉洲。日暮乡关何处是?烟江波上使人愁。 </content> </poem> <poem NO="Z002" title="望庐山瀑布"> <content> 日照香炉生紫烟,遥看瀑布挂前川。飞流直下三千尺,疑是银河落九天。 </content> </poem> </poems>
上述文档的内部DTD将属性NO声明为ID类型的,XML的数据部分是合法有效的。如果将两个元素poem属性NO的取值都改为“Z001”和“Z002”或分别改为“001”和“002”,这两种情况都将提示相关的错误信息。
注意 ID类型的属性必须设置为#IMPLIED或#REQUIRED,不能是#FIXED或默认的,不能为ID提供默认值。
4.IDREF/IDREFS
IDREF属性的值指向文档中其他地方声明的ID类型的值。在应用程序中,通过ID和IDREF实现交叉引用,而不必多次重复整个元素。
IDREF属性的值与ID类型的取值约束一致,而且它必须与文档中的某个ID属性具有相同的值。IDREF值不能指向文档中不存在的ID。IDREFS与IDREF类似,是IDREF的复数,每个IDREF之间通过空格隔开。
下述代码用于实现任务【描述2.D.6】,创建并使用带IDREF(IDREFS)属性的内部DTD,演示IDREF的使用。
【描述2.D.6】 IDREFdemo.xml
<?xml version="1.0" encoding="GB2312"?> <!DOCTYPE family [ <!ELEMENT family (person+)> <!ELEMENT person EMPTY> <!ATTLIST person relID ID #REQUIRED parentID IDREFS #IMPLIED name CDATA #REQUIRED > ]> <family> <person relID="P01" name="Bernie"/> <person relID="P02" name="Rose"/> <person relID="P03" parentID="P01" name="Joson"/> <person relID="P04" name="Tom"/> <person relID="P05" name="Barbara"/> <person relID="P06" parentID="P04 P05" name="Barbie"/> </family>
上述文档中,通过交叉引用,应用程序(或XML解析器)可以通过元素的parentID属性找到其引用的person元素。
5.枚举类型
枚举类型(Enumerated)不需要使用关键字,它只是将所有可能的属性取值列举出来,并以竖线(“|”)分隔。枚举类型的每一个可能值都必须遵循XML的名称规范。
下述代码用于实现任务【描述2.D.7】,创建并使用带枚举类型属性的内部DTD,演示枚举类型的使用。
【描述2.D.7】 ENUMdemo.xml
<?xml version="1.0" encoding="GB2312"?> <!DOCTYPE students [ <!ELEMENT students (student+)> <!ELEMENT student EMPTY> <!ATTLIST student name CDATA #REQUIRED age CDATA #REQUIRED sex (male | female) "male" > ]> <students> <student name="Tom" age="17"/> <student name="Rose" age="19" sex="female"/> </students>
上述文档中,元素student的sex属性被声明为枚举类型,可能的取值为male或female,并被设置默认取值为male。在实际应用中,元素student的sex属性的取值必须为上述二者取值之一。
2.2.3 实体
实体(Entity)是XML中一种可以节省大量时间的机制,它的作用类似于Word中的“宏”,也可以将其理解为模板,使用者可以预先定义一个实体,然后在一个文档中多次调用,或者在多个文档中调用同一个实体。简单来说,实体就是XML引用一个数据项的方法,它通常是文本,也可以是二进制数据。
一般情况下,实体的命名遵循XML名称规范即可,使用实体的好处在于以下两个方面。
* 减少出错率,文档中多个相同的部分只需要输入一遍即可。
* 提高维护效率,比如多个文档都包含地址信息的实体,如果需要修改这个地址信息,只要修改最初定义的实体语句即可。
XML定义了两种类型的实体:一种是预定义实体;另一种是自定义实体。
1.预定义实体
在XML中,对于XML语言定义的某些特殊字符(如尖括号)需保留定义,另外,有些字符是不可打印的。XML提供了一些预定义的实体,如表2-5所示,使用者可以在XML文档中利用这些实体表示特定的字符,并保证不产生冲突。因此在元素的文本内容中,可以用实体表示一些特殊字符,以免它们在解析时与文档的标记混淆。
表2-5 XML的预定义实体
在XML中,任何字符也都可以表示为数字引用。具体方法是在符号“&#”之后加上字符的数字值和分号(它们之间没有空格)。例如,大于号也可以表示为“>”。
2.自定义实体
使用者也可以根据需要在DTD中定义一个实体,然后在文档中通过引用来使用它。
自定义实体的语法格式为:
<!DOCTYPE rootname [ <!ENTITY entity-name "entity-content"> ]>
下述代码定义了一段地址信息:
<!DOCTYPE ADDRESS [ <!ENTITY ADDRESS "山东路家乐福"> ]>
如果此地址信息的内容和他人所需的信息来源于同一个文件,也可以使用外部调用的方法。引用格式如下:
<!DOCTYPE ADDRESS [ <!ENTITY ADDRESS SYSTEM "http://www.sample.com/ADDRESS.xml"> ]>
定义好的实体在文档中的引用语法为“&实体名;”。
下述代码用于实现任务【描述2.D.8】,创建并使用带自定义实体的内部DTD,演示自定义实体的使用。
【描述2.D.8】 ENTITYdemo.xml
<?xml version="1.0" encoding="GB2312"?> <!DOCTYPE greeses [ <!ELEMENT greeses (greese+)> <!ELEMENT greese (name, letter, description?)> <!ELEMENT name (#PCDATA)> <!ELEMENT letter (#PCDATA)> <!ELEMENT description (#PCDATA)> <!ENTITY alpha "α"> <!ENTITY beta "β"> ]> <greeses> <greese> <name>alpha</name> <letter>α</letter> <description>第一个希腊字母</description> </greese> <greese> <name>beta</name> <letter>β</letter> <description>第二个希腊字母</description> </greese> <greese> <name>小于号</name> <letter><</letter> </greese> </greeses>
通过IE浏览器查看结果如图2-1所示。
图2-1 实体显示结果
需要注意的是,实体允许嵌套,如下述代码是允许的:
<!ENTITY man "Mr."> <!ENTITY name "Johnson"> <!ENTITY welcome "&man; &name;">
但是,实体不允许循环,如下述代码是错误的:
<!ENTITY man "Mr.&name;"> <!ENTITY name "&man; Johnson">
当XML解析器处理这种情况时,会陷入死循环,用户在定义实体时,务必要严防这种事情的发生。
小结
通过本章的学习,学生应该能够学会:
* DTD是一套关于标记符的语法规则,是XML 1.0规格的一部分。
* DTD是一种保证XML文档格式正确的有效方法。
* DTD文件是一个ASCII的文本文件,后缀名为.dtd。
* DTD可以在XML内部定义也可以在外部定义。
* DTD提供了XML文档所包含的元素、属性和实体及相互关系的定义。
* DTD的元素类型有ANY类型、EMPTY类型、#PCDATA类型、父元素类型和混合元素类型。
* 常用的DTD属性类型有CDATA、NMTOKEN/NMTOKENS、ID、IDREF/IDREFS、枚举类型等。
* XML中实体可以理解为模板,使用者可以预先定义一个实体,然后在一个文档中多次调用,或者在多个文档中调用同一个实体。
* 实体是XML引用一个数据项的方法,它通常是文本,也可以是二进制数据。
* XML定义了两种类型的实体。一种是预定义实体;另一种是自定义实体。
练习
1.下列选项中,______是合法的元素名。
A.TOM B.1abc C.18 D.[abc]
2.对于下面的代码,______不是PRODUCT元素的子元素。
<!ELEMENT PRODUCT (PRODUCTNAME, DESCRIPTION, PRICE, QUANTITY)>
A.PRODUCTNAME B.QUANTITY
C.DESCRIPTION D.NUMBER
3.DTD文档中,定义属性的关键字是______。
A.DOCTYPE B.ATTLIST
C.ELEMENT D.ENTITY
4.下列选项中,______是预定义实体(多选)。
A.& B.&name; C.< D.©right;
5.DTD文档中,某元素属性的特点为必须包含该属性,该属性应定义为______。
A.#REQUIRED B.#IMPLIED
C.#FIXED value D.默认值
6.在DTD中,元素类型通过_________标记声明,实体类型通过_________标记声明。
7.DOCTYPE声明由以下部分组成:_________、_________、可选的外部标记符,以及_________。
8.属性类型设为ID,表明该属性的取值_________。
9.XML定义了两种类型的实体,一种是_________;另一种是_________。
10.IDREF属性的值指向文档中其他地方声明的_________类型的值。
11.分析下列XML实例,上机编写外部DTD文档,并进行验证。
<?xml version="1.0" encoding="GB2312"?> <班级> <学生 学号="C95001"> <姓名>李明</姓名> <性别>男</性别> <年龄>18</年龄> </学生> <学生 学号="C95002"> <姓名>张燕</姓名> <性别>女</性别> <年龄>19</年龄> </学生> <学生 学号="C95003"> <姓名>赵彦</姓名> <性别>男</性别> <年龄>20</年龄> </学生> </班级>
12.分析下列DTD文档,上机编写有效的XML实例,并进行验证。
<!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 "人民日报"> <!ENTITY PUBLISHER "人民日报出版社"> <!ENTITY COPYRIGHT "人民日报出版社版权所有> ]>