**定义:**DTD定义了文档的逻辑结构,规定了文档中所使用的元素、实体、元素的属性、元素与实体之间的关系。其作用主要表现在以下几个方面。
(1) 使用DTD可以提供一种统一的格式。XML的可扩展性为文档的作者提供了很高的灵活性,可有时候需要的是统一,要求某一类文档具有相同的结构。
(2) 使用DTD可以保证数据交流和共享的顺利进行。
(3) DTD使用户能够不依赖具体的数据就知道文档的逻辑结构。在没有XML文档的时候,也可以根据DTD为XML文档编写样式单,编写处理程序,这样可以有效地提高工作效率。
(4) 使用DTD可以验证数据的有效性。DTD对文档的逻辑结构进行了约束,这种约束可以比较宽松,也可以十分严格。可以根据DTD检查数据,以验证其是否符合规定和要求,这可以保证数据的正确和有效。
4.2 DTD元素
DTD中描述的基本部件是元素和属性,它们负责确定XML文档的逻辑结构。元素表示一个信息对象,而属性表示这个对象的性质。所有元素中有且只有一个根元素,其他的元素都是它的子元素,除根元素外,每个元素都被其他元素包含,一个元素可以有几个不同类型的子元素。
4.2.1 元素的基本类型
元素的基本类型大致可分为两种,一种称为简单型,另一种称为复合型。简单型具有文本数据,即可析字符数据,该类型也称为上下文中的“#PCADTA”;复合型可以包含其他元素和文本数据。
1. 简单型
“#PCDATA”(Parsed Character Data)表示标记的内容是可解析文本,所谓的可解析文本就是非标记文本。用“#PCDATA”规范了的元素不能再包含子元素。例如How do you do是不包含标记的文本,而How do you do
就不是可解析的数据类型,因为其中包含有标记和
。另外DTD文档中不同元素定义的次序没有先后关系,但文档的语法对大小写敏感。
“#PCDATA”的声明格式:
【例4.1】 “#PCDATA”的用法,代码如源程序code4_1.xml所示。
]>
其显示结果如图4.1所示。
2. 复合型
复合型元素与简单型元素相对,复合型元素可包含其他元素。
图4.1 “#PCDATA”的用法
【例4.2】 复合型元素的用法,代码如源程序code4_2.xml所示。
]>
其显示结果如图4.2所示。
图4.2 复合型元素的用法
4.2.2 元素的声明
1. 元素声明的基本语法
元素的声明格式:
其中,Element_Name为声明的元素名称,Element_Defination为元素内容格式的定义。
合法的元素声明语句如:
2. 空元素的声明
在第3章中已介绍了空标记的使用方法,那么在DTD中如何对与其对应的空元素进行声明呢?其声明格式:
例如下面的语句:
3. 不限定元素内容的声明
ANY是DTD中使用很频繁的一个关键字,特别是对于文档根元素的声明。在定义一个DTD文档时通常很难准确地确定一个元素是否具有子元素的情况,此时一般的做法是指定该元素的子元素为ANY型(表示可以是任意的元素),这样在它之中可以包含任何数据、任何声明的子元素及其数据和子元素的组合。
ANY元素的声明格式:
而在文档刚开始定义时,并不明确将来的应用领域中会有多少个元素,所以唯一的做法就是标记为ANY类型,表示可以包含任何元素和可解析数据。例如:
然后在文档的实际开发过程中再逐步完善该元素的子元素的具体定义,将ANY关键字替换掉。
【例4.3】 ANY的用法,代码如源程序code4_3.xml所示。
]>
显示结果与例4.1的相同。
文档中能有多个ANY型的元素吗?这是完全可以的,因为ANY型的元素不一定是根元素。
【例4.4】 包含多个ANY型元素的XML文档,代码如源程序code4_4.xml所示。
]>
ANY型的元素在文档中应尽量少使用,因为这与XML文档的数据结构性相违背。但多数情况之下在定义一个元素的所有子元素之前,总是首先以ANY代替,最后再以实际的子元素替代ANY关键字,定义出具体的DTD文档。
4. 子元素列表的设定
在XML中有一种针对复合元素的最为严格的设定方法,称为子元素列表的设定。这种方式下,元素都拥有哪些子元素、每个子元素出现的次数和位置都有明确的规定,在具体文档实现时,必须严格执行。
子元素列表的设定语法如下:
其中“(Child_Element1, Child_Element2,…)”部分为Element_Name所拥有的子元素列表。
【例4.5】 子元素列表的设定,代码如源程序code4_5.xml所示。
]>
上面程序是一个不合法的文档,原因在于,标记
5. 可选择的子元素
有些时候,需要在两个或多个互斥的元素中进行选择。即多选一的情况,如一个人的性别可以是男或女,两者中只能有一种情况。DTD有专门的语法来处理这种情况,其语法格式如下:
其中,“(Child_Element1|Child_Element2|…)”部分为选择性元素组合,具体使用时必须要在这个列表中选择其一。
【例4.6】 选择性元素列表的设定,代码如源程序code4_6.xml所示。
]>
]>
其显示结果如图4.3所示。
在实际应用中,使用元素组可能不是最好的方案。这时也可以先将准备分组的元素定义为一个复合元素,再在原来的元素中引用刚定义的复合元素,这样文档的结构更清晰。
图4.3 元素组的使用
【例4.8】 较好的方案,代码如源程序code4_8.xml所示。
]>
其显示结果如图4.4所示。
图4.4 较好的方案
混合型元素的存在破坏了文档的层次结构化,不利于应用软件对XML文档的处理,在XML文档开发过程中,它可以作为一个不成熟的DTD文档,一步一步地在XML文档中添加元素,边添加边测试其正确性,这时可将尚未处理的部分作为字符数据组织到一个混合型元素中,以便使文档通过测试。但在文档最后完成时,要通过添加新元素的方法来清除这种非结构化信息。
4.3 DTD属性
什么是属性?简单来讲就是元素的附加特性,在DTD中声明元素时,也必须对该元素的属性进行声明。
4.3.1 属性的声明
在DTD中,属性的声明格式:
其中,为属性声明的关键字,Element_name为元素名,Attribute_name为属性名,TYPE是属性类型,Default_value为没有设定属性值时的默认值。
【例4.9】 属性的声明,代码如源程序code4_9.xml所示。
]>
其显示结果如图4.5所示。
图4.5 属性的声明
在声明属性时有以下需要注意的事项。
(1) 可以多次为一个元素声明其中所包含的属性。如在XML文档中有如下语句:
属性声明可以为
(2) 属性的声明在文档中的次序没有严格的要求,可位于与其相连的元素声明之前或之后。如在XML文档中有如下语句:
属性声明可以为
(3) 所有元素的属性,都要在各自所对应的标记中声明。如在XML文档中有如下语句:
属性声明可以为
(4) 属性有4种不同类型的默认值,可在属性声明中的Default_value部分指定。
① default:表示使用提供的默认值,default不是一个关键字,它代表一个预设的字符串。
此例句表示当在XML文档中省略了对bookinfo元素的bookcategory属性值进行设定时,该属性的默认值就是“文艺”。
② #REQUIRED:表示属性值必须指定。
③ #IMPLIED:表示元素的这个属性可用可不用。
④ #FIXED:表示元素的这个属性值是一个固定值,且必须是指定的值。
4.3.2 属性的类型
在属性的声明中TYPE部分为属性的类型设定,DTD中属性的类型有10种,下面将对这些数据类型进行逐一的介绍。
1. CDATA型
CDATA型表明属性值为不包含“<”和“””的任意字符串,如果属性值中需要包含“<”和“””,则可使用特殊字符来代替。
2. Enumerated型
如果属性值并不是任意的字符串,而是在几个可能的值中进行选择,如书籍的“类别”属性,其值可为“文艺”,也可为“自然科学”,而不可能为其他情况时,则可以将书籍的“类别”属性设定为Enumerated型。
3. ID型
当元素的某个属性值是不能重复时,如书籍的ISBN属性、个人的“身份证号”属性等,要定义这样的属性则需使用属性的ID类型。在一个XML文档中,所有元素的ID类型属性的属性值必须是唯一的,不可重复,另外,一个元素不能有超过一个ID类型的属性。
4. IDREF与IDREFS型
IDREF为Identifier Reference的缩写,IDREF与ID类型属性的关系为子元素与父元素的关系,即IDREF类型属性的值必须是其他元素的ID类型属性的值,且该ID类型属性的值必须在文档的其他地方被设定过。IDREFS类型属性的属性值可有多个,每一个都必须是在文档其他地方被设定了的ID类型属性的值,而这多个属性值之间用空格隔开。
【例4.10】 IDREFS的使用,代码如源程序code4_10.xml所示。
teach IDREFS #IMPLIED
>
number ID #REQUIRED
>
]>
丁潇
PowerBuilder
AutoCAD
XML
其显示结果如图4.6所示。
图4.6 IDREFS的使用
5. ENTITY与ENTITIES型
ENTITY类型的属性提供了把外部二进制形式的文件(如.jpeg、.mp3等)和外部不可解析实体链接到XML文档的功能。因此其属性值也必须为不可解析的链接外部实际数据的通用实体名。ENTITIES类型属性的属性值可由多个不可解析的外部实体名称组成,各实体名称之间使用空格隔开。
【例4.11】 ENTITY与ENTITIES的使用,代码如源程序code4_11.xml所示。
>
ID #REQUIRED
>
]>
本例不是所有XML浏览器都可以自动识别的通用格式,仅仅某些浏览器和应用程序可能采用的在文档中嵌入非XML数据的方法而已。
6. NMTOKEN与NMTOKENS型
NMTOKEN类型的属性限定属性值是有效的XML名称,这个属性值可以由英文、数字、“.”、 “_”、“-”、“:”等组成,这里有几点需要注意。
(1) 不能包括空格。
(2) 以上字符中除“:”以外,其他字符都可以作为开头字符。
(3) “:”可以出现在中间,但由于它是命名域的关键字符,所以一般不提倡使用。
正因为NMTOKEN类型的属性对于字符的严格要求,使得它在一些常用编程语言中,都是合法的数据,这就为这些编程语言对XML文档数据的操作打下了良好的基础。
NMTOKENS类型的属性具有与NMTOKEN属性相近的形式。这种类型的属性可以使如下情况合法——属性由若干XML名称组成,彼此间由空格隔开。通常可为使用NMTOKEN属性相同的理由而使用NMTOKENS属性,但仅仅在需要多个名字的时候。
7. NOTATION型
XML文档中引入了外部不可解析的实体后,解析器无法解析这些二进制文件,这时,就可以使用NOTATION类型的属性为这些二进制文件指定与其对应的应用软件以对其进行处理。
【例4.12】 NOTATION的使用,代码如源程序code4_12.xml所示。
]>
4.4 DTD中的实体
在第3章中已经接触了预定义实体,在DTD中,还存在自定义实体,定义后依照一定的语法规则可在XML文档或DTD中进行引用。
4.4.1 实体的概念
实体是包含了文档片段的虚拟存储单元,可用来存储XML声明、DTD、其他形式的文本及二进制数据等。简单来讲就是一段代码或数据的代称,这个代称即为实体的名字。当需要在文档中引用某段代码或数据时,可以引用与这段代码或数据相对应的实体名称来代替实体的具体内容。具有正确性检查功能的XML处理器在提交文档给最终应用程序之前或在显示文档以前,将先把所有不同的实体引用替换为与其对应的具体内容,从而构成一个结构完整的文档。
4.4.2 实体的分类
按照实体的具体内容来分类,实体可分为可解析与不可解析两类。可解析实体的具体内容为简单的字符、数字、文本块,而不可解析实体的具体内容则为图片、声音等二进制文件。
按照逻辑存储来分类,实体可分为内部实体与外部实体两类。内部实体的内容是在文档内部设定的;而外部实体则是一个外部独立的物理存储对象,如某个外部文件。
按照使用的范围来分类,实体可分为一般实体与参数实体两类。一般实体都用来构成文档的具体内容,可出现在XML文档中,也可出现在DTD中;而参数实体只能出现在DTD中,不能出现在XML文档中。
1. 内部一般实体
内部一般实体就是在文档实体内部定义和使用的实体,其内容通常是一段文本字符。这种实体要在DTD中通过DTD语句的定义,可以在XML文档中使用,也可在DTD中使用。其定义的语法格式如下:
其中,为关键字,Eentity_name为实体名称,Replacement为实体所代替的文本内容。引用内部一般实体的方法如下:
&Eentity_name;
【例4.13】 内部一般实体的使用,代码如源程序code4_13.xml所示。
]>
其显示结果与4.2节的图4.2相同。
当内部一般实体在DTD中引用时,有以下几方面需注意。
(1) 不能在元素及属性的声明中引用内部一般实体,如下面的语句即为非法的:
(2) 在语句中不能出现循环,如下面的语句即为非法的:
其中,URL为引用的外部实体的URL地址。引用外部一般实体也与引用内部一般实体的方法一样:
&Eentity_name;
假如有一个XML文档code4_14out.xml如下:
可以通过下面的例子把它作为外部实体来引用。
【例4.14】 外部一般实体的使用,代码如源程序code4_14.xml所示。
]>
&pub;
其显示结果仍与4.2节的图4.2相同。
在引用外部一般实体时,有以下几方面需注意。
(1) 因为在一个文档中需引用某些外部文件,所以该文档声明中的standalone属性不再是默认值yes,而应该为no。
(2) 作为外部一般实体的文档,若使用的是XML的默认字符集即UTF-8或UNICODE,则可以在文档头部不进行XML声明,否则,必须有XML声明,且声明时,一定要说明ecoding属性。
3. 内部参数实体
内部参数实体是指在独立的外部DTD文档的内部定义和使用的实体,其内容为仅能为DTD而非XML文档内容的书写文本。这里提到参数实体与前面所讲的一般实体是有区别的:
(1) 在引用形式上,一般实体的引用为“&Eentity_name;”,而参数实体的引用则为“%Eentity_name;”
(2) 在引用范围上,一般实体可在XML文档中引用,也可在DTD中引用,而参数实体只可在DTD中引用。
定义内部参数实体的语法格式如下:
【例4.15】 内部参数实体的使用,代码如源程序code4_15.dtd所示。
【例4.16】 外部参数实体的使用,代码如源程序code4_16.xml所示。
程序code4_16_1.dtd为
%pub;
程序code4_16_2.dtd为
经过几次引用,显示结果仍然同4.2节的图4.2相同。
4.5 使用DTD
前面几节讲述了DTD各组成部分的语法格式。本节将讲述如何引用DTD。引用DTD的方法有两种:内部DTD引用与外部DTD引用。内部DTD引用即在XML文档中直接设定DTD,外部DTD引用则是在XML文档中引用一个扩展名为.dtd的独立文件。
4.5.1 内部DTD
内部DTD的定义语句和XML文档在同一个文档中,且通常放置在XML文档的头部。在定义内部DTD时,定义内部DTD的语句要全部放置在文档类型声明中,其语法格式:
…
]>
其中,为关键字,Root_Element_Name为根元素名,[…]部分则为内部DTD定义语句。如例4.1,即是一个包含内部DTD的XML文档。
4.5.2 外部DTD
外部DTD就是有关文档定义的语句都被独立出来放在一个外部文件中,对其进行独立的管理。跟据其内容的性质,可分为两种,一种是私有文件,指未公开的、属于某组织或个人私有的DTD文件;另一种是公开文件,是指由国际标准组织如ISO等或可发布技术建议的组织如W3C等,为某一领域所制定的公开的标准DTD。
引用私有DTD文件的语法格式:
其中,URL为外部DTD文件的相对路径或绝对路径,该语句必须置于XML文档的头部,且在XML文档处理指令中要将standalone属性值设定为no。如例4.14。
引用公开DTD文件的语法格式:
其中,PUBLIC为公开DTD文件的关键字。Public_Dtd_name为公开DTD文件的文件名,这个文件名由4个部分组成:第一部分为DTD的发布者,若是ISO发布,则第一部分为ISO;若是非ISO的标准组织发布,则为“+”;若是非标准组织发布,则为“-”。第二部分为所有者的名字。第三部分为表明这个DTD文件的主要内容或类别的简要文本。第四部分为所使用的语言,该语言标志必须是ISO639所定义过的标准标志。这4部分之间用“//”隔开。Public_Dtd_URL为公开DTD文件的相对路径或绝对路径。
4.5.3 混合DTD
所谓混合DTD,即为内部DTD与外部DTD混合使用。在DTD使用的实际情况中, 很少使用完全标准的DTD,往往是公司先为所有的开发小组提供一分公共的DTD作为外部DTD,然后各个成员在实际的使用过程中再进行扩展定义,这时的扩展定义常常是使用内部DTD来实现的。
【例4.17】 混合DTD的使用,代码如源程序code4_17.xml所示。
]>
4.6 综 合 实 例
现在对XML文档及DTD有了一定的认识,下面将使用本章所学知识设计一个图书信息管理系统的XML文档,使其具有严格的标记语言。首先要做出图书信息管理系统的标记结构图,如图4.7所示。
图4.7 图书信息管理系统的标记结构图
再根据以上标记结构图进行设计,设计过程如下:
(1) 分别设计作者、书籍、出版社信息的DTD语句;
(2) 使用外部实体的方式设计系统的DTD文档;
(3) 根据设计好的DTD文档,编写XML文档;
(4) 生成完整的XML文档。
4.6.1 DTD片段
【例4.18】 图书信息管理系统。
(1) 程序code4_18_1.dtd,与作者相对应的DTD片段。
作者信息中authors根元素下有author子元素,author子元素又包含了a_name、sex、email这3个子元素,其中email子元素可有可无,也可有数个。author子元素有两个属性,分别为作者的ID和作者所编书籍的ISBN,且这两个属性的属性值必须指定。
(2) 程序code4_18_2.dtd,与书籍相对应的DTD片段。
书籍信息中books根元素下有book子元素,book子元素又包含了b_name、price两个子元素。book子元素有一个属性,即书籍的ISBN,且这个属性的属性值必须指定。
(3) 程序code4_18_3.dtd,与出版社相对应的DTD片段。
作者信息中publishers根元素下有publisher子元素,publisher子元素又包含了p_name、address两个子元素。publisher子元素有一个属性,即其出版社所印书籍的ISBN,且这个属性的属性值必须指定。
4.6.2 系统DTD文档
程序code4_18.dtd,XML文档直接引用的DTD。
%author;
%book;
%publisher;
在XML文档直接引用的DTD中,用到外部参数实体,从而将作者、书籍、出版社相对应的DTD片段与XML文档直接引用的DTD组成一个整体,以便XML主文档的引用。
4.6.3 XML文档片段
程序code4_18_1.xml,作者信息XML文档片段。
程序code4_18_2.xml,书籍信息XML文档片段。
程序code4_18_3.xml,出版社信息XML文档片段。
北京市东城区沙滩后街55号
北京市宣武区右安门西街8号
4.6.4 生成完整的XML文档
程序code4_18.xml,XML主文档。
]>
&authors;
&books;
&publishers;
在XML主文档中运用了外部一般实体,将作者、书籍、出版社信息的XML文档片段与主文档联系起来,并将主文档与系统DTD文件关联在一起,以组成一个结构完整的XML文档。运行程序code4_18.xml,最终显示结果如图4.8所示。