2.2 XML文档的整体结构
上面的代码已经给出了3份XML文档,除了第一份是格式不良好的XML文档之外,另外两份都是格式良好的XML文档(有效的XML文档首先必须是格式良好的)。作为一份格式良好的XML文档,必须遵守下面几条规则。
2.2.1 有且仅有一个根元素
XML文档的第一行通常是XML文档的声明。由于XML文档是一种标准的结构化文档,可以转换成DOM(Document Object Model)树,其根节点对应DOM树的根节点。因此,XML文档必须有一个根元素,而且只能有一个根元素。
一份XML文档可以只有根元素。有效的XML文档的所有内容都必须包含在唯一的根元素中,根元素包含着文档中所有的文本和元素。下面的XML文档是格式良好的:
这份XML文档相当特殊,它只有一个根元素,其中不包含任何东西,但它依然是格式良好的。
在XML文档里有这样两个基本概念:标签和元素。标签是一个由小于号(<)、 标识名和大于号(>)组成的字符单元,分为开始标签和结束标签,结束标签比开始标签多了一条斜线(/),例如<abc>就是一个开始标签,而</abc>就是一个结束标签。而元素则通常由开始标签、元素内容和结束标签组成,例如<abc>haha</abc>就是一个元素。
一份XML文档不管有多么复杂,都只能有一个根节点。也就是说,一份XML文档只能转化为树,而不能转化为森林。
XML文档只有一个根元素,这可以保证该文档具有“自我描述性”,例如如下XML文档:
程序清单:codes\02\2.2\games.xml
上面的XML文档的所有内容都处于<喜欢的游戏… />这个元素内部,因此就好像要告诉别人“这是一份介绍我喜欢的游戏的文档”。
2.2.2 元素必须合理结束
与HTML文档不同,XML文档要求所有元素都必须合理结束,合理结束有以下两种情况:
所有开始标签都必须有配对的结束标签。
空元素必须严格使用空元素语法。
例如下面的文档就是格式不良好的:
因为上面的文档根元素没有合理结束,所以它不是一个格式良好的XML文档。
需要指出的是,XML的语法严格区分大小写,也就是说<book>和</Book>标签并不匹配,因此下面的XML文档也是格式不良好的:
从上面的介绍可以看出,所有的XML元素通常都需要两个标签——开始标签和结束标签,而且开始标签和结束标签的标签名必须绝对相同,开始标签和结束标签的区别是结束标签多了一条斜线(/)。
XML元素的开始标签和结束标签之间的内容就是该元素的“子内容”,这里的“子内容”既可是普通字符内容,也可是子元素。
如果不需要为XML元素指定“子内容”,也就是说要让该XML元素是一个空元素,则可以使用空元素语法。空元素语法不需要将开始标签和结束标签分开写,可将二者放在一起。空元素语法如下:
可以看出,空元素语法是直接在标签后添加斜线。
2.2.3 元素之间必须合理嵌套
整个XML文档都必须包含在一个XML根元素里,这个根元素可以包含任意多个子元素,每个子元素又可包含多个子元素,就这样一层层展开,最后组成一棵DOM树。也就是说,XML要求所有元素之间的结构关系必须非常清晰——相互有影响的元素之间要么是父子关系,要么是兄弟关系,这样才可保证元素与元素之间合理嵌套。
例如下面的XML代码片段:
我们可以非常清楚地看出,<message…/>元素下有3个子元素,分别是<from…/>、<to…/>和<content…/>,这3个子元素之间又是平等的兄弟关系。
因此我们可以将上面的代码片段转换为如图2.5所示的结构树。
图2.5 结构化文档对应的树
由此可见,合理嵌套的元素之间一定有清晰的结构关系。下面的XML文档就不算合理嵌套:
上面的代码片段中有<a…/>和<b…/>两个元素,但它们之间的结构关系不清楚,我们无法准确分辨<a…/>和<b…/>之间是父子还是兄弟关系,这就是没有合理嵌套。
2.2.4 元素的属性必须有值
XML文档允许为XML元素指定属性,属性可以为XML元素提供更多的额外信息。例如如下代码:
上面的book元素使用desc属性为该元素增加了额外信息。
除此之外,通过使用属性可以简化原本复杂、臃肿的XML文档。例如在Spring 1.1配置文件中经常可以看到类似如下配置片段:
在上面的配置片段中,<bean…/>元素下有两个<property…/>子元素,分别用于为名为sun的Bean配置name和age属性值。注意<property…/>元素下的<value…/>子元素包含字符串内容,在这种情况下,我们可以将上面的配置文件改为使用属性的形式:
不难发现,第二种形式的XML文档简洁多了,但传递的信息丝毫没有减少,这就是将子元素改为属性的魅力。Spring框架的作者也发现了属性具有这个优势,因此从Spring 1.2开始完全支持使用第二种写法进行配置管理。
注意
将子元素改写为属性有一个前提条件,只有子元素包含的内容完全是字符串才可以。不仅如此,由于XML文档只是信息的载体,其中的信息必须可由有效的程序进行处理才行,因此读者在进行这种转换之前必须事先确认。
例如前面介绍web.xml时指出,配置一个Servlet需要如下代码片段:
根据前面的介绍,我们可以将上面的配置片段简化为如下形式:
第二种写法明显简洁多了,但实际上可以吗?实际不行,因为web.xml文件由Web服务器负责解析,而Web服务器只接受第一种形式的XML数据,因此这种写法在实际应用中行不通。
XML元素可以接受属性,但所有属性都必须有属性值,而且每个属性值都必须使用引号引起来,这里的引号既可以是单引号,也可以是双引号,但要注意引号必须匹配:使用引号包含一个属性值时,要么全部是单引号,要么全部是双引号,不要单引号、双引号混合使用。例如下面两个元素中属性的写法是合法的:
但下面的写法就是错误的:
注意
看惯了HTML文档的读者,可能发现HTML文档中很多元素的属性没有使用引号包括,却依然不影响使用效果。这是因为虽然HTML文档和XML文档同是标记语言,但浏览器为了保证较好的兼容性,对HTML文档的约束要松得多。
XML文档元素的属性没有顺序要求,每个属性放在前面一点或后面一点都没有关系,也就是说同一个元素里的多个属性是无序的。由于元素的多个属性是无序的,因此同一个元素中不能出现两个同名属性,也就是说元素的属性不能重复。
下面两个水果元素完全相同:
注意
XML元素里的多个属性之间是无序的,因此同一个元素不可包含多个同名的属性;XML元素内包含的子元素则是有序的,因此同一个元素可以包含多个同名的子元素。这正如Java集合框架里的Set和List,其中Set代表元素无序、集合元素不可重复的集合,而List则代表元素有序、集合元素可以重复的集合。