迅腾国际XML语言第2章XML文档基本语法12第二章XML文档基本语法本章要点:文档类型定义(DTD)文档类型声明DTD的合法性可在文档间共享的通用DTD使用名称空间(Namespace)预习问题备忘录:迅腾国际XML语言第2章XML文档基本语法132.1本章简介XML作为一种元标记语言,是一种描述标记语言的语言。元标记语言(也叫标记集)需要通过文档类型定义(DTD)来定义,这正是本章要讲述的内容。XML文档与其DTD相比较的过程被称为合法性检验。如果文档符合DTD中的约束,这个文档就被认为是合法的,否则就是不合法的。2.2文档类型定义在上一章中,我们详细介绍了一个“形式良好的”(well-formed)XML文档应该满足哪些要求。“形式良好”是对XML文档的基本要求,它使得XML文档结构清晰、完整,便于应用程序对其进行解析。除此之外,“形式良好的”XML文档还应基于信息描述,并能够体现数据信息之间逻辑关系,而且还可以确保文档的易读和易搜索性。这就需要XML文档遵循所谓“形式良好”要求的种种语法规则,即必须遵守文档类型定义DTD(DocumentTypeDefinition)中定义的种种规定。DTD实际上是“元标记”这个概念的产物,它描述了一个标记语言的语法和词汇表,也就是定义了文档的整体结构以及文档的语法。简而言之,DTD规定了一个语法分析器,用于解释一个“有效的”XML文档所需要知道的所有规则的细节-—元素清单、属性、标记、文档中的实体及其相互关系。2.2.1一个DTD文档在这一节中,我们先展示给大家一个完整的文档定义实例,请大家直观感受一下DTD定义的文法并思考其中的奥妙。下面的示例XML文档“内部DTD.xml”包含了内部的DTD定义:示例代码2-1:内部DTD?xmlversion=1.0encoding=GB2312standalone=yes?!--DTD定义--!DOCTYPE公司[!--元素定义--!ELEMENT公司(雇员)+!ELEMENT雇员(姓名,雇佣日期,项目清单)!ELEMENT姓名(#PCDATA)!ELEMENT雇佣日期(#PCDATA)!ELEMENT项目清单(项目)*!ELEMENT项目(产品,价格)!ELEMENT产品(#PCDATA)!ELEMENT价格(#PCDATA)!--属性定义--!ATTLIST项目清单数量CDATA#REQUIRED!ATTLIST雇员部门CDATA#REQUIRED全职CDATA#IMPLIED]!—内容定义--公司雇员部门=市场部全职=是迅腾国际XML语言第2章XML文档基本语法14姓名李东/姓名雇佣日期2005-01-15/雇佣日期项目清单数量=2项目产品打印机/产品价格$111.00/价格/项目项目产品笔记本/产品价格$9897.00/价格/项目/项目清单/雇员雇员部门=客服部姓名王权/姓名雇佣日期2005-10-02/雇佣日期项目清单数量=1项目产品扫描仪/产品价格$200.00/价格/项目/项目清单/雇员/公司此文档“内部DTD.xml”包含了两个主要部分:一是开始部分的内部DTD定义,二是后半部分的XML内容定义。DTD定义部分含义如下:公司可以由一个或者多个雇员组成,用“+”号表示。雇员有两个属性:部门(必须有,REQUIRED)、全职(可忽略,IMPLIED)。雇员包含了三个子元素:姓名,雇佣日期、项目清单,前两个类型为#PCDATA,即它可以包含任何字符数据。特别指出的是项目清单元素,它既包含了子元素:项目,可以是零到多个(“*”号表示),还包含了一个必须的属性:数量。项目子元素包含了两个子元素:产品、价格。XML内容定义部分是完全按照文档中的内部DTD的种种规定编辑的整体结构和标记语法。提示:还可以把DTD定义部分单独放在另外一个文件中,方法参见下一节。2.2.2DTD的引用方式在上一小节的DTD定义案例中,DTD定义部分和XML内容部分被合并在一个文档里。下面我们看一下如何在XML中引入DTD文档。所有的XML文档都是由序言和文本体构成的,序言中通常包含XML声明,另外,在序言中还可以包含DTD定义,而文本体则是描述具体的数据信息。2.2.2.1内部DTD迅腾国际XML语言第2章XML文档基本语法15最简单的使用DTD的方法是在XML文件的序言部分加入一个DTD描述,加入的位置是紧接在XML处理指示之后。一个包含DTD的XML文件的结构为:?xmlversion=1.0encoding=GB2312standalone=yes?!DOCTYPE根元素名[元素描述]第一节案例就是一个完整的包含内部DTD的XML文件。不过,为每一个XML文件加入一段DTD定义是相当烦琐的,而且,更多的情况下,我们会为一批XML文件定义一个相同的DTD。例如,对于报社中的每篇稿件,它们都具有相同的格式,可以采用一个统一的DTD,如果为每一篇稿件单独定义DTD既麻烦又不利于格式统一。为此,XML规范为我们提供了解决这个问题的方法,它就是外部DTD。2.2.2.2外部DTD使用外部DTD的好处是:它可以方便高效地被多个XML文件所共享。只要写一个DTD文件,就可以被多个XML文件所引用。事实上,当许多组织需要统一它们的数据交换格式时,它们就是通过外部DTD来完成的,这样做不仅简化了输入工作,还保证当你需要对DTD做出改动时,不用一一去改每个引用了它的XML文件,只要改一个公用的DTD文件就足够了。使用外部DTD需要注意以下两个方面:1、XML声明中必须说明这个文件不是独立的,即standalone属性的属性值不再是yes了。?xmlversion=1.0encoding=GB2312standalone=no?2、在DOCTYPE声明中,应该加入SYSTEM属性:!DOCTYPE联系人列表SYSTEM外部DTD.dtd例如:上面的URL是一个绝对路径,除此以外,它还可以是一个相对路径,如!DOCTYPE联系人列表SYSTEMfclml.dtd提示:编写外部DTD的便捷方法:可以把DTD信息从现有的XML文件中分离出来,粘贴到另一个DTD文件中,再将分离出来的DTD文档以SYSTEM的方式导入到指定的XML文件中。这样,你就既得到了一个DTD文件又得到了一个有效的XML文件。以下代码是从第一节的XML文件中分离出来的外部DTD“雇员.dtd”的定义形式:示例代码2-2:外部DTD?xmlversion=1.0encoding=GB2312?!--DTD元素定义--!ELEMENT公司(雇员)+!ELEMENT雇员(姓名,雇佣日期,项目清单)!ELEMENT姓名(#PCDATA)!ELEMENT雇佣日期(#PCDATA)!ELEMENT项目清单(项目)*!ELEMENT项目(产品,价格)!ELEMENT产品(#PCDATA)!ELEMENT价格(#PCDATA)!--DTD属性定义--!ATTLIST项目清单数量CDATA#REQUIRED!DOCTYPE联系人列表SYSTEM迅腾国际XML语言第2章XML文档基本语法16!ATTLIST雇员部门CDATA#REQUIRED全职CDATA#IMPLIED将第一节的XML文件改为使用外部DTD定义方式,其形式应该是:示例代码2-2:使用外部DTD?xmlversion=1.0encoding=GB2312standalone=no?!DOCTYPE公司SYSTEM雇员.dtd公司雇员部门=市场部全职=是姓名李东/姓名雇佣日期2005-01-15/雇佣日期项目清单数量=2项目产品打印机/产品价格$111.00/价格/项目项目产品笔记本/产品价格$9897.00/价格/项目/项目清单/雇员……/公司注意:上述案例中XML文件和DTD文件应该在同一级目录。2.2.3掌握DTD定义元素在合法的XML文档中使用的每项标记都要在DTD的元素声明中加以声明。元素声明指明了元素名称和元素可能的内容。内容规格使用一种简单的语法精确地指明文档中允许什么和不允许什么,如可以指明它可能出现不止一次,可能出现或可能不出现,或必须出现至少一次。注意,DTD的要求很严格,没有明确允许的就是禁止的。一个DTD不仅要告诉语法分析器它所关联的XML文件的根元素是什么,而且还要告诉语法分析器文件的内容和结构,说清文件结构中的每一个细节。为了定义这些细节,我们必须展开DTD中元素说明部分,使用元素类型声明(ETD)来声明所有有效的文件元素。元素类型声明不但说明了每个文件中可能存在的元素,给出了元素的名字,而且给出了元素的具体类型。一个XML元素可以为空,也可以是一段纯文本,或可以有若干个子元素,而这些子元素同时又可以有它们的子元素。DTD正是通过元素之间的父子关系,描述了整个文件的结构关系。请再看一个简单的DTD定义的案例“联系人列表.xml”:示例代码2-3:DTD定义语法?xmlversion=1.0encoding=GB2312standalone=yes?!DOCTYPE联系人列表[!ELEMENT联系人列表(联系人)!ELEMENT联系人(姓名)!ELEMENT姓名(#PCDATA)迅腾国际XML语言第2章XML文档基本语法17]联系人列表联系人姓名张三/姓名/联系人/联系人列表元素类型声明应该采用如下的结构:!ELEMENT元素名元素内容描述因此,在前面的例子里,可以在文件序言中通过如下方式定义“联系人列表”这个元素:?xmlversion=1.0encoding=GB2312standalone=yes?!DOCTYPE联系人列表[!ELEMENT联系人列表(联系人)]联系人列表…/联系人列表这个DTD定义了一个XML文件,它只有一个根元素,名为“联系人列表”,这个元素可以有“联系人”子元素。通常,编辑时缩进无关紧要,元素声明的顺序也不重要。下面这一文档类型声明的作用与上面的声明相同:!DOCTYPE联系人列表[!ELEMENT联系人(姓名)!ELEMENT姓名(#PCDATA)!ELEMENT联系人列表(联系人)]2.2.3.1ANY编写XML文档首先要标识根元素,“联系人列表”是基本元素。可以用!DOCTYPE对根元素进行声明:!DOCTYPE联系人列表[]但是,这只是说根元素是“联系人列表”,而没有提到元素能或不能包含的内容,所以还需要在元素声明中声明“联系人列表”元素的形式,例如:!ELEMENT联系人列表ANY注意,所有的元素类型声明都以“!ELEMENT(区分大小写)”开头而以“”结束。上例中,关键词ANY(区分大小写)表明所有可能的元素以及可解析的字符数据都可以是“联系人列表”元素的子元素。在上面的例子中,元素“联系人列表”被定义为“可以”包含其他元素(ANY)。但“有效的”XML文件规定,文件中所使用的任何元素都必须在DTD中给出定义,否则,仍不能被语法解析器所接受。为了使元素“联系人列表”中还可以包含其它元素,从而使前面的那个文件是“有效的”,我们定义了元素“联系人”和“姓名”。示例代码2-4:ANY的用法?xmlversion=1.0encoding=GB2312standalone=yes?!DOCTYPE联系人列表[!ELEMENT联系人列表ANY迅腾国际XML语言第2章XML文档基本语法18!ELEMENT联系人(姓名)