(本系列文章是我学习的过程中,整理出来的笔记,如有错漏,看官请一定不吝回复,让我能认识自己的不足,并改进错误。非常感谢!)
本章大概内容:
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)。
在该类型的元素声明时,通过内容模型来指定在其内容上的约束。内容模型是决定子元素类型和子元素出现顺序的一种简单语法。