本章大概内容:
1、为什么需要DTD
2、XML文档如何使用DTD
1)内部定义DTD
2)关联外部DTD
3、DTD的结构
1)元素类型声明
2)属性列表声明
3)实体声明
4)记号声明
对于一个格式良好的XML文档,我们只能保证这个文档的格式符合XML规范,但是元素与元素的关系,元素与属性的关系,属性的取值,我们就无法保证了。对于一个格式良好的文档,如果只是在有限的应用中使用,或者是用于存储和传输,那么它也能能够很好的满足我们的应用,但是如果要其它的用户了解你所写的XML文档,或者与其它应用进行数据的交换,那么就有必要提供一种机制,来保证我们写的XML文档和别人所写的XML文档在结构上是相同的,元素与元素之间的关系是正确的,属性的取值也是符合要求的,那么这种机制在XML规范中已经为我们提供了,那就是前一章中介绍过的文档类型声明中提到的DTD。
DTD(Document Type Definition),文档类型定义。
在XML标准中,描述了如何创建DTD,以及如何将它与根据它的规范所编写的XML文档相关联,并且还定义了XML处理器应该如何对DTD进行处理。有了DTD就可以检测XML文档的结构是否正确。
DTD为XML文档的编写者与处理者提供了共同遵循的原则,使得与文档相关的各种工作有了统一的标准。
如何在XML文档中引入DTD
通过在XML文档中包含文档类型声明,来建立当前文档和DTD的关联。当进行有效性验证的XML处理器读到该声明时,它获取DTD,并根据其中定义的规则对文档进行检验。文档类型声明必须位于XML声明之后,且在根元素(文档元素)之前。不过,在XML声明和文档类型声明之间可以插入注释和处理指令。
我们可以直接在XML文档中定义DTD,也可以通过URI引用外部的DTD文件,或者同时采用这两种方式。
上一章中,已经学习过如何通过包含文档类型声明来建立与DTD的关联。现在来分析一下这两种包含方式。
在XML文档内部给出DTD的方式:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE OrganizationChart [
<!ELEMENT OrganizationChart (Name,Office)>
<!ELEMENT Name (#PCDATA)>
<!ELEMENT Office (#PCDATA)>
]>
<OrganizationChart>
<!--OrganizationChart是该XML文档的document element-->
<Name>Toone,INC.</Name>
<Office>zhuhai</Office>
<!--因为DTD中定义了Name,Office两个元素的顺序,Office元素不能放在Name元素的前面,否则不是有效的XML文档-->
</OrganizationChart>
文档类型声明由<!开始,后面紧跟一个关键字DOCTYPE,然后是文档根元素的名字,接下来是标记声明块,标记声明块放在中括号[]之间,由一个或者多个标记声明构成,最后由>结束。
在DTD中,所有的关键字都是大写的。不过,在DTD中定义的元素和属性的大小写是可以任意制定的,但是要注意,因为XML文档是大小写相关的,所以一旦给一个元素命名,那么在整个文档中要使用相同的大小写。例如,organizationchart和OrganizationChart是不同的两个元素名。
在XML文档中定义DTD,比较直观,修改也比较方便,而且不用担心XML处理器找不到DTD,但是它也有一些缺点:
1、在文档中定义DTD会导致文档本身的长度增加,在传输数据时,即使不需要验证文档的有效性,这些声明也要一起传输。
2、如果多个XML文档要共用同一个DTD,我们就需要在每一个文档中加入DTD。
引进外部DTD方式:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE OrganizationChart SYSTEM "dtdTest.dtd" >
<OrganizationChart>
<Name>Toone,INC.</Name>
<Office>zhuhai</Office>
</OrganizationChart>
对应DTD内容为:
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT OrganizationChart (Name,Office)>
<!ELEMENT Name (#PCDATA)>
<!ELEMENT Office (#PCDATA)>
在文档类型声明时,用管间质SYSTEM或PUBLIC来指出外部DTD文件的位置,使用SYSTEM关键字的声明语法如下:
<!DOCTYPE 根元素的名字 SYSTEM "外部DTD文件的URI">
SYSTEM关键字表示文档使用的是私有的DTD文件,“外部DTD文件的URI”可以是相对URI或者绝对URI。例如上面的例子使用的就是相对URI:
<!DOCTYPE OrganizationChart SYSTEM "dtdTest.dtd" >
使用PUBLIC关键字的声明语法如下:
<!DOCTYPE 根元素的名字 PUBLIC "DTD的名字" "外部DTD文件的URI">
PUBLIC关键字用于声明公共的DTD,并且这个DTD还有一个名称,"DTD的名称"也称为公共标识符(public identifier)。这个DTD可以存放在某个公共的地方,XML处理程序会根据名称按照某种方式去检索DTD,如果XML处理器不能根据名称检索到DTD,就会使用"外部DTD文件的URI"来查找该DTD。例如Java web开发的web.xml中的DTD声明(版本不同会稍有不同,我们只关注它的结构):
<!DOCTYPE web-app PUBLIC '-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN'
'http://java.sun.com/dtd/web-app_2_3.dtd'>
DTD名称与XML名称略有不同,他们只能包含ASCII字母和数字符号、空格、回车符、换行符和一些标点符号:-'()+,/:=?;!#@*$_%.
公共DTD名称要遵守一些约定。如果一项DTD是ISO标准,它的名称要以字符串"ISO"开始。如果是一个非ISO的标准组织批准的DTD,它的名字以加号(+)开始。如果不是标准组织批准的DTD,它的名称以连字符(-)开始。这些开始字符或字符串后接双斜杠(//)和DTD所有者的名字(比如上面例子的Sun Microsystems,Inc.),之后是另一个双斜杠和DTD描述的文档类型,接着优势一个双斜杠后接ISO 639语言标识符,如EN表示英语,ZH表示中文。例如:
<!DOCTYPE OrganizationChart PUBLIC "-//Jason Chen//DTD organization chart 1.0//ZH" "dtdTest.dtd">
在上一章我们提到,如果我们的文档不依赖于外部文档,在XML声明中,可以通过standalone="yes"来声明这个文档是独立的文档。如果文档依赖于外部文档,可以通过standalone="no"来声明。当我们使用外部DTD文件时,就需要将属性standalone的值设置为"no"。
在实际应用中,很少使用standalone属性,它的主要用途是作为XML处理器行业其他应用程序的标志,表示是否需要获取外部内容。如果文档依赖于外部文档,即使我们不使用standalone属性,XML处理器也能很好地进行处理。
DTD的结构:
DTD的结构一般由以下四种声明构成:
1、元素类型声明
2、属性列表声明
3、实体声明
4、记号声明
一个典型的文档类型定义文件会吧所要创建的XML文档的元素结构、属性类型、实体引用等预先进行定义。
下面分别介绍这四种声明。
1、元素类型声明:
一个DTD不仅要告诉XML处理器它所对应的文档根元素,而且还要告知处理器,文档的内容和结构,描述清楚文档结构中的每一个细节。
元素类型声明不但说明了每一个文档中可能存在的元素,给出了元素的名称,而且给出了元素的具体类型。
一个XML元素可以为空,也可以只包含字符数据,还可以有若干个子元素,而这些子元素同时又可以拥有它们的子元素。
元素类型声明采用如下的语法格式:
<!ELEMENT 元素名称 元素内容说明>
元素内容说明可以指明五种可能的元素内容形式:#PCDATA、子元素、混合内容、EMPTY和ANY。
下面详细说明每一种元素内容说明。
#PCDATA:
关键字#PCDATA说明元素包含字符数据。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE OrganizationChart [
<!ELEMENT OrganizationChart (Name,Office)>
<!ELEMENT Name (#PCDATA)>
<!ELEMENT Office (#PCDATA)>
]>
<OrganizationChart>
<Name>Toone,INC.</Name>
<Office>ZhuHai</Office>
</OrganizationChart>
子元素:
当一个元素只包含子元素,而没有字符数据时,则称此元素类型具有元素型内容(element content)。
在该类型的元素声明时,通过内容模型来指定在其内容上的约束。内容模型是决定子元素类型和子元素出现顺序的一种简单语法。