W3CHINA.ORG讨论区--关于DTD详细应用学习

来源:百度文库 编辑:神马文学网 时间:2024/05/01 09:23:00
将DTD引入“有效的”XML文件中
    


“形式良好”是对XML文件的基本要求,它使得XML文件结构清晰、完整,便于处理程序对其进行解析,进一步可以简化处理程序的编写工作,并加快浏览的速度、减少浏览所需占用的内存空间。正所谓“没有规矩,不成方圆”。

然而,即便你已经可以保证写的XML文件是一个“形式良好的”XML文件了,它仍然未必能够体现XML的精髓。XML的精髓是什么呢?对,就是我们前面讲到的基于信息描述的、能够体现数据信息之间逻辑关系的、可以确保文件的易读性和易搜索性的自定义标记!从这一章中你将看到,使得你的XML文件遵循所谓“形式良好”要求的种种语法规则,这只是“万里长征走了第一步”。一个完全意义上的XML文件不仅应该是“形式良好的”,而且还应该是使用了这些自定义标记的“有效”的XML文件。

一个“有效的”文件首先应该是“形式良好”的。但这还远远不够,它还要往前更进一步。一个XML文件必须遵守文件类型描述DTD(Document Type Definition)中定义的种种规定。DTD实际上是“元标记”这个概念的产物,它描述了一个置标语言的语法和词汇表,也就是定义了文件的整体结构以及文件的语法。简而言之,DTD规定了一个语法分析器为了解释一个“有效的”XML文件所需要知道的所有规则的细节。

这个“规则”可以非常简单,仅仅列出所有有效的元素,例如元素、标记、属性、实体;也可以非常复杂,不但列出这些元素,还指出这些元素之间的内在联系,例如说明元素X元素中必须还包含元素Y或元素Z,但不能同时包含两个元素。

“我们前面强调了XML是大小写敏感的,这对于HTML的老手可能有点麻烦。例如,XML的处理指示 

中所有单词必须都是小写的;可是所有DTD中的关键字都必须是大写的,例如ELEMENT、ATTLIST、#REQUIRED、#IMPLIED、NMTOKEN、ID等等。幸运的是,你自己的元素和属性的大小写可以由你任意指定,但一旦指定了,你必须从一而终,在整个文件中使用相同的大小写。例如,如果你给一个元素起名叫“BOOKS”,那么这个元素和“Books”并不相同。

——Ken Sall”
 

一般习惯里,除非使用中文标记,否则我们或者全部都使用大写字母,或者象在VC中常用的那样,元素名字的第一个字母是大写,后面每个单词的第一个字母为大写,如BookList;属性字母的第一个字母为小写,但后面每个单词的第一个字母仍都采用大写,如listAuthor。请看下面例子:


        genre NMTOKEN #IMPLIED
        listAuthor NMTOKEN #REQUIRED
        lastUpdated NMTOKEN #REQUIRED >
 


讲到这里,不知各位读者是否已经能够区分“形式良好的”XML文件和“有效的”XML文件。如果大家对采用“有效的”XML文件的必要性还有所怀疑的话,让我们一起考虑一下下面这段中文:

棕色 扑向
那只 一只 狐狸 
动作敏捷的 狗 。
懒惰的 
 

正如你所见,所有的单词和标点都符合中文的词法,甚至说都是有明确语意的词汇,它们代表了“形式良好的”元素。但是,你明白我要表达的意思吗?在这种混乱的顺序之下,可能那些明确的单词和标点对你也失去了应有的意义。连人都难于理解一段“形式良好的”话,更不要说什么计算机了。

为了使这句话成为能读得懂的话,上面那些词汇的组织必须遵守中文句子的语法规定,譬如符合主、谓、宾的顺序,修饰语放在中心词之前等等。修改一下,上面的句子应该成为下面的形式:

一只动作敏捷的棕色狐狸扑向一只懒惰的狗。
 

好了,现在知道这句话想表达什么意思了吧?

在XML所描述的置标语言中,DTD便提供了语法规定,以便给各个语言要素赋予一定的顺序。为了说明特定的语法规则,DTD采用了一系列正则式,语法分析器将这些正则式与XML文件内部的数据模式相匹配,从而判别一个文件是否是有效的。匹配被严格执行,因此,如果XML文件中有任何信息不符合DTD的规定,都不会通过。

还记得我们曾说过XML脱胎于SGML文件吗?其实,一个“有效的”XML文件就是一个“形式良好的”SGML文件,也就是说,符合DTD中定义的语法是SGML文件的基本要求。从这个意义上说,XML把合法文件的范围扩大了,既包括“有效的”XML,也可包括“形式良好的”XML。

好了,相信大家现在已经明白什么叫DTD了。下面我们就开始详细学习XML中这个不可或缺、大显身手的部分。


内部DTD     

在正式学习DTD的定义方法之前,我们先来看一下定义应该放在文件的什么地方。

正如我们前面所提到的,所有的文件都是由序言和文件体构成的。序言中包含了XML声明,而文件体中则是具体的数据信息,还可以含有一些处理指示。实际上,我们在前面隐掉了重要的一点:在序言中还可以包含DTD定义。

最简单的使用DTD的方法是在XML文件的序言部分加入一个DTD描述,加入的位置是紧接在XML处理指示之后。一个包含DTD的XML文件的结构为:


    元素描述
    ]>
文件体....... 

这样,我们就定义了一个文件,它以DOCTYPE中规定的根元素名作为其根元素的名字。

回忆一下,在第一章中我们曾经举过一个包含客户联系方式信息的XML文件。在这个例子中,我们可以在序言中如下加入DTD定义:


    元素描述
    ]> 


一个完整的XML文件为:

client.xml

        
        
        
        
        
        
        
        
        
        
        
    ]>

<联系人列表>
  <联系人>
    <姓名>张三
    001
    <公司>A公司
    zhang@aaa.com
    <电话>(010)62345678
    <地址>
      <街道>五街1234号
      <城市>北京市
      <省份>北京
    
  

  <联系人>
    <姓名>李四
    002
    <公司>B公司
    li@bbb.org
    <电话>(021)87654321
    <地址>
      <街道>南京路9876号
      <城市>上海市
      <省份>上海
    
  
 

不过,如果为每一个XML文件加入一段DTD定义,是相当繁琐的。而且,更多的情况下,我们会为一批XML文件定义一个相同的DTD。例如,对于报社中的每篇稿件,它们都有相同的格式,可以采用一个统一的DTD,为每一篇单独定义既麻烦,又不利于统一格式。好在XML规范为我们提供了解决这个问题的方法,它就是外部DTD。

外部DTD
    


一个DTD既可以是内部的,包含在一个“形式良好的”XML文件中(standalone=“yes”),采用前面一节中的形式;也可以是外部的,作为一个外部文件被引用(standalone=“no”)。

外部DTD的好处是:它可以方便高效地被多个XML文件所共享。你只要写一个DTD文件,就可以被多个XML文件所引用。事实上,当许多组织需要统一它们的数据交换格式时,它们就是通过外部DTD来完成的。这样做不仅简化了输入工作,还保证当你需要对DTD做出改动时,不用一一去改每个引用了它的XML文件,只要改一个公用的DTD文件就足够了。不过需要注意,如果DTD的改动不是“向后兼容”的,这时原先写的那些XML文件可能就会出问题了!

为了引用一个外部DTD,必须修改XML声明和DOCTYPE声明。

XML声明中必须说明这个文件不是自成一体的,即standalone属性的属性值不再是yes了。

      encoding="GB2312" 
      standalone = "no"?> 

在DOCTYPE声明中,应该加入SYSTEM属性:

SYSTEM "外部DTD文件的URL"> 

例如:

SYSTEM "http://www.mydomain.com/dtds/fclml.dtd
"> 

上面的URL是一个绝对路径,除此以外,它还可以是一个相对路径,如:

SYSTEM "fclml.dtd"> 

它说明这个DTD文件和引用它的XML文件在同一个目录下。或者,这个DTD文件还可能在XML文件的父目录的子目录DTD下,表示为:


SYSTEM "../dtds/fclml.dtd"> 

使用这种方法,你可以方便地把DTD文件从你的XML文件中分离出来,粘贴到另一个文件fclml.dtd中。这样,你就得到一个DTD文件和一个有效的XML文件。

仍然回到前面那个包含客户联系方式信息的XML文件,如果使用外部DTD,其形式应该变为下面这个样子。

DTD文件fclml.dtd:











 

XML文件client.xml:


    SYSTEM "fclml.dtd">

<联系人列表>
<联系人>
<姓名>张三
001
<公司>A公司
zhang@aaa.com
<电话>(010)62345678
<地址>
<街道>五街1234号
<城市>北京市
<省份>北京
100001

<联系人>
<姓名>李四
002
<公司>B公司
li@bbb.org
<电话>(021)87654321
<地址>
<街道>南京路9876号
<城市>上海
<省份>上海
200002


 

在这一节里,我们将为每个XML文件定义的DTD推广到一个系统内可共享的DTD。在下一节里,我们还可以将这个推广进一步推而广之,扩大到行业内甚至公众使用的公用DTD。

公用DTD
    


在前面一节中我们讲过,使用外部DTD时,要在DOCTYPE中使用关键字SYSTEM。实际上,SYSTEM不是引用外部DTD的唯一方法,这个关键字主要用于引用一个作者或组织所编写的众多XML文件中通用的DTD。还存在一种外部DTD,它是一个由权威机构制订的,提供给特定行业或公众使用的DTD。因此,另一个引用外部DTD的办法是使用关键字PUBLIC,引用这一类公开给公众使用的DTD。

当使用关键字PUBLIC进行引用时,这个外部DTD还需要得到一个标识名。引用公共DTD的形式为:

 

请见下面例子:

 

这个DTD标识的命名规则和XML文件的命名规则稍有不同。具体地说,DTD名称只能包含字母、数字、空格和下面的符号:_%$#@()+:=/!*;?。同时,DTD名称还必须符合一些标准的规定。例如,ISO标准的DTD以“ISO”三个字母开头;被改进的非ISO标准的DTD以加号“+”开头;未被改进的非ISO标准的DTD以减号“-”开头。

无论是哪一种情况,开始部分后面都跟着两个斜杠“//”及DTD所有者的名称。在这个名称之后又是两个斜杠“//”,再然后是DTD所描述的文件的类型。最后,在又一对斜杠之后是语言的种类(参见ISO 639)。例如下面这个公用DTD的引用:

"http://www.mydomain.com/dtds/fclml.dtd"> 

看上去的确比较复杂,不过没关系,对于DTD的命名通常不是它的引用者的任务,XML文件的编写者只要在自己的文件中把事先定义好的DTD名称放在相应的位置中就可以了。

实体属性类型与参数实体
    


在上一章中,我们介绍过实体的概念。相信你还能回忆起来,实体在XML中充当着宏或别名的角色。

实体最根本的作用是帮助你为一大段文本创建一个别名,这样,在文件的另一个位置需要引用这段文本时,仅需要指向它的别名就可以了。可想而知,这样一来,用于重新输入这段文本的大量时间就被节约下来了。它还意味着一旦需要修改,仅需要在一个地方作改动,就完成了全局的改动。

我们还提到,实体分为一般实体和参数实体两种类型,它们都可以定义为内部的也可以用关键字SYSTEM定义为外部的。实体的定义必须出现在引用之前,而且要注意正确嵌套,不能出现循环引用的情况。在DTD中,这两种类型的实体都得到了广泛的应用。 

实体属性类型 
实体类型的属性值属于一般实体,如前所述,它的定义方式是:

 

或利用SYSTEM定义外部实体,方式为:

 

引用方式为:

&实体名; 

使用关键字ENTITY,则声明一个属性是实体类型,它的取值为已定义的实体。请看下面例子:

      encoding="GB2312" 
      standalone = "yes"?>
    
    
    
    
    ]>

<文件>
    <电影 来源 = "&BladeRunner;">
 

参数实体 
参数实体专门用在DTD中。定义方式是:

 

或:

 

引用方式为:

%实体名; 

使用参数实体,可以方便元素和属性的声明。例如:



 

最后提醒大家注意,不要以为实体属性类型的定义与DTD有关,所以它使用的就是参数实体。参数实体只能在DTD中使用,而对于任何元素属性值的指定(除了缺省值外),都是在XML文件正文中进行的,因此实体属性值仍属于一般实体。

转帖网址:http://bbs.w3china.org/dispbbs.asp?boardID=1&ID=22530