17.2 深入认识XML文档
和所有标记语言一样,XML也有其特定的语法格和细节部分,包括XML的声明、XML元素、XML标签及其属性、XML处理指令、XML文档中的注释以及文档定义类型等基本概念和用法。XML是一个比较简单的描述数据的方法,但并不意味着XML很简单,实际上,关于XML的内容是非常丰富的,本节将从基本和实用两个方面出发,尽可能多地介绍XML文档的各个方面。
17.2.1 XML声明
XML的作用就是告诉XML处理程序这个文件是按照XML文件的标准对数据进行描述的。当创建一个XML文件时,通常要以一个XML声明作为开始。是因为XML声明在文件中是可选内容,可加可不加,但W3C推荐加入声明,所以通常把XML声明作为XML文件的第一行。一个最简单的XML声明如下。
<?xml version = "1.0"?>
XML的声明由“<?”开始,以“?>”结束。在“<?”后面紧跟着处理指示的名称,在这里是“xml”。XML声明中要求必须指定version的属性值,这个值定义了XML的版本。另外,声明中还有两个可选属性,分别是standalone和encoding。因此,一个完整的XML声明如下所示。
<?xml version="1.0" standalone="no" encoding="UTF-8"?>
·version属性,在一个XML的声明中必须包括version属性指明所采用的XML的版本号,而且,它必须在属性列表中排在第一位。由于当前的XML最新版本是1.0,所以目前看到XML声明无一例外都是version="1.0"。
·standalone属性,这个属性表明该XML文件是否和一个独立的声明文件配套使用。如果该属性值为“yes”,说明没有另外一个配套的DTD文件(这个文件将在后续有所介绍)来配套使用。相反,如果这个属性置为“no”,则有可能有这样一个文件。
·encoding属性,所有XML语法分析器都要支持8位和16位的编码标准。而且,XML支持一个更庞大的编码集合。实际应用中常见的编码是GB2312(简体中文码)和UTF-8(Unicode Translation Format),采用哪种编码取决于XML文件中用到的字符集。在前文的例子中,使用了UTF-8编码来声明XML文档的字符集。
17.2.2 XML元素
XML元素是XML文档的精髓,元素是XML文件内容的基本单元。从语法上讲,一个元素包含一个起始标记、一个结束标记以及标记之间的数据内容。其形式是<标记>数据内容</标记>。例如如下关于国籍元素的例子。
< 国籍> 中国</ 国籍>
在17.2节的例子中有关于图书名称(title)的元素如下。
<title>Learning XML</title>
元素中还可以嵌套其他元素,在17.2节的代码17-1中,books元素就嵌套了book元素,而book元素又嵌套了title、author、publisher和price元素。
在代码17-1中,books元素从文件头的声明之后开始一直到文件尾,包含了文件中的所有数据信息,这个books元素称为根元素。所有XML文件都至少包含一个形式良好的根元素。根元素又称为文件标记,紧跟在XML声明之后,根标记必须是一个非空的标记,其中包含了整个文件的数据内容。如果一个XML文档没有根元素,无论该文档包含什么样的信息,XML解析器都会拒绝它。
注意 XML中开始和结束标记之间的文字称为“字符数据”,标签内(即<>之间)的文字称为“标记”。例如<title>Learning XML</title>,Learning XML是字符数据,而title是标记。<title>和</title>都被看做是XML标签。
所有XML元素都必须有一个结束标签,忽略结束标签是不合法的。这一点和HTML完全不一样,在HTML中,有些标签可以不用对应结束标签,示例如下。
<p>This is a paragraph <p>This is another paragraph
这里表示段落的<p>标签就没有对应的结束标签。而在XML中,每一个标签都必须有结束标签。读者可能已经注意到17.2节的示例XML文档中,表示XML声明的标签<xml>就没有结束标签。这是正确的,因为XML声明并不算是XML文档的一部分,它不是一个XML元素,所以它不应该有结束标签。
XML元素不能重叠,例如如下XML代码。
<aaa><bbb> XML 元素示例 </aaa></bbb>
这段XML代码就是错误的,因为在标签<aaa>中开始的标签<bbb>必须在标签<aaa>之内结束,如下代码才是正确的XML代码。
<aaa><bbb> XML 元素示例 </bbb></aaa>
这也就是说,XML的元素要正确地嵌套。
17.2.3 标记和属性
XML的标记和HTML的标记在形式上大体相同,符号“<”和“>”之间的内容都称为标记。其基本形式如下。
< 标记名 属性名=" 属性取值">
XML对于标记的语法规定比HTML要严格得多。首先,标记是必不可少的。任何一个形式良好的XML文件中至少要有一个元素。
注意 和HTML不同,XML对标签的大小写十分敏感。<Word>和<word>在XML中是两个不同的标签。
XML要有正确的结束标记。结束标记除了要和开始标记在拼写和大小写上完全相同,还必须在前面加上一个斜杠“/”。例如,如果开始标记是<ADDRESS>,结束标记应该是</ADDRESS>。
因为XML严格要求开始标记和结束标记匹配,所以,HTML中的<BR>、<HR>的元素形式在XML中是不合法的。但是,当一对标记之间没有任何文本内容时,可以不写结束标记,而在开始标记的最后惯以斜杠“/”来确认,这样的标记称为“空标记”。例如,HTML中的标记<HR>在XML中的使用方式应该是<HR/>。
标记名称要合法,标记应该以字母、下划线“_”或冒号“:”开头,后面跟字母、数字、句号“.”、冒号、下划线或连字符“-”,中间不能有空格,而且任何标记不能以“xml”起始。不过,最好不要在标记的开头使用冒号,尽管它是合法的,但可能会带来混淆。另外,在XML1.0标准中,允许使用任何长度的标记,不过,现实中的XML处理程序可能会要求标记的长度在一定范围内。
XML中可以为标签指定属性和属性的值,就像HTML中那样。XML文档中的属性有两个主要规则,其一,属性必须有值;其二,属性值必须用引号括起,属性值可以使用单引号、双引号括起,但要始终保持一致。如果属性值包含单引号或双引号,则可以使用另一种引号来括起该值(如name="Doug's car"),或使用实体"代表双引号,使用'代表单引号。
注意 实体是一个符号(如"),XML解析器会用其他文本代替该符号。
XML标记中可以包含任意多个属性。在标记中,属性以“名称/值”对的形式出现,属性名不能重复,属性名与属性值之间用等号“=”分隔,且取值用引号括起来,示例如下。
<person sex="female">
这段代码为标签person的sex属性取值为female。
17.2.4 注释
注释可以出现在XML文档的任何位置,甚至可以出现在根元素的前面或后面。XML文档注释以<!--开始,以-->结束,这个用法和HTML一致。例如下面的XML代码片段中使用了注释。
01 <!-- 这些是图书的有关信息 --> 02 <book> 03 <title>Learning PHP5</title> <!-- 图书的名称 --> 04 <author>David</author> 05 <publisher>White Water Press</publisher> 06 <price>29.90</price> 07 </book> 08 <!-- 图书信息结束 -->
【代码解析】这段XML代码片段中加入了3处注释。
注意 在注释文本中不能出现“-”或“--”,因为XML处理器可能把它们和注释结尾标志“-->”相混淆。
不要把注释文本放在标记之中,如代码将注释“<!--这些是图书的有关信息-->”放在了标签<book>之中,这是错误的。
<book <!-- 这些是图书的有关信息 --> > <title>Learning PHP5</title> <author>David</author> <publisher>White Water Press</publisher> <price>29.90</price> </book>
同样的道理,不要将注释放在实体声明中,也不要放在XML声明之前。前面的内容讲过,XML声明永远是XML文件中的第一行。
注意 注释是不能嵌套使用的。
在使用一对注释符号表示注释文本时,要保证其中不再包含另一对注释符号。例如如下示例是不合法的。
<book> <title>Learning PHP5</title> <!-- 以下是图书作者的信息 <!-- 作者的姓名 --> --> <author>David</author> <publisher>White Water Press</publisher> <price>29.90</price> </book>
说明 XML解析器对于注释中的一切内容都会视而不见,注释中出现的标记也一同被忽略。这为一下除去XML文档中的一大部分元素提供了一种方法,可以将这部分元素使用注释括住。
17.2.5 处理指令
处理指令是用来给处理XML文档的应用程序提供信息的。也就是说,XML分析器可能对它并不感兴趣,而把这些信息原封不动地传给XML应用程序。这个应用程序应该会解释这个指示,按照它所提供的信息进行处理,或者再把它原封不动地传给下一个应用程序。正如前面所看到的,XML声明就是一个处理指令。
XML有很多处理指令,它们都遵循如下所示的格式。
<? 处理指示名 处理指示信息?>
例如代码17-1中的XML声明<?xml version="1.0"encoding="GB2312"?>就是一个处理指令。由于XML声明的处理指示名是“xml”,因此其他处理指示名不能再用“xml”。例如下面的代码,是另外一个处理指令。
<?cocoon-process type="sql"?>
cocoon是来自Apache软件基金会(Apache Software Foundation)的XML处理框架。当cocoon处理XML文档时,它会寻找以cocoon-process开头的处理指令,然后相应地处理XML文档。在该示例中,type="sql"属性告诉cocoon,XML文档包含一个SQL语句。
17.2.6 实体简介
在前面介绍标记属性时,提到了实体这一概念,本小节对实体再做一些简要的说明。可以这样理解实体,实体是文档用来替换一些特殊标记符号的字符串。XML中或HTML中常见的实体如下所示。
·实体<代表小于符号<,lt就表示less than。
·实体>代表大于符号>,gt就表示greater than。
·实体"代表一个双引号”。
·实体'代表一个单引号'(或撇号)。
·实体&代表一个“与”符号&。
注意 实体以符号“&”开头,以英文分号“;”结束。
17.2.7 文件类型定义
通过对前面内容的学习,读者应该了解到,XML的精髓是基于信息描述的、能够体现数据信息之间逻辑关系的、可以确保文件的易读性和易搜索性的自定义标记。一个完全意义上的XML文件不仅应该是“形式良好的”,而且还应该是使用了自定义标记的XML文件。定义用来表示数据的标记,最常用的方法就是实用文档定义类型(Document Type Definition),即所谓的DTD。
DTD指定在XML文档中出现的元素、这些元素出现的次序、元素相互嵌套的关系以及XML文档结构的其他详细信息,DTD是XML规范的一部分。一个XML文件必须遵守文件类型描述DTD(Document Type Definition)中定义的种种规定。DTD定义了文件的整体结构以及文件的语法。简而言之,DTD规定了一个语法分析器为了解释一个“有效的”XML文件所需要知道的所有规则的细节。这些规则有时很简单,有时会很复杂。比如说,列出所有有效的元素、标记、属性和实体,这就是一个比较简单的规则。又如,指出元素之间的内在联系,说明某个元素必须包含的其他元素,就是一个比较复杂的规则。
DTD用来指定XML文档的基本结构,最简单的使用DTD的方法是在XML文件的序言部分加入一个DTD描述,加入的位置紧接在XML处理指示之后,其结构如下。
<?xml version = "1.0" encoding="UTF-8"> <!DOCTYPE 根元素名[ 元素描述 ]> 文件体
这段代码表示该XML文档实用DOCTYPE中规定的“根元素名”作为其根元素的名字。一个DTD不仅要告诉XML分析器该XML文件的根元素是什么,而且还要告诉语法分析器文件的内容和结构,说清文件结构中的每一个细节。为了描述这些细节,必须展开DTD中元素说明部分,使用元素类型声明(Element Type Definition,ETD)来声明所有有效的文件元素。ETD结构如下。
<!ELEMENT 元素名 元素内容描述>
在上述例子中,可以通过如下方式定义“图书信息”这个元素。
<?xml version = "1.0" encoding="UTF-8"> <!DOCTYPE books[ 图书信息 <!ELEMENT books ANY> ]> <books> </books>
这个DTD定义XML文件只有一个根元素,ANY表示这个元素可以有任何类型的子元素,也可以是纯文本,还可以为空。
注意 除了根元素外,在定义其他元素时使用关键字ANY都是不好的习惯。
通常需要在XML文档中的根元素之内加入其他元素,这个XML文档才是有效的,才是可以被XML解释器所能接受的XML文档。
为了使元素“books”中还可以包含其他元素,还需要定义元素“book”(即具体的图书)和元素“title”(即图书的名称),代码如下。
<?xml version = "1.0" encoding="UTF-8"> <!DOCTYPE books[ 图书信息 <!ELEMENT books (book)> <!ELEMENT book (title)> <!ELEMENT title (#PCDATA)> ]> <books> <book> <title>Learning PHP5</title> </book> <books>
至此,已经定义了一个XML文档,它还有一个名为books的根元素,根据DTD的描述,该根元素中可以包含book元素,book元素又包含子元素,名为title。而title只能包含纯文本数据,这在DTD中用#PCDATA来体现。如下是一个加入了DTD描述的较为完整的XML文档示例,它以代码17-1为基础。
01 <?xml version = "1.0" encoding="UTF-8"> 02 <!DOCTYPE books[ 03 图书信息 04 <!ELEMENT books (book)*> 05 <!ELEMENT book (title,author,publisher,price)> 06 <!ELEMENT title (#PCDATA)> 07 <!ELEMENT author (#PCDATA)> 08 <!ELEMENT publisher (#PCDATA)> 09 <!ELEMENT price (#PCDATA)> 10 ]> 11 12 <books> 13 <book> 14 <title>Learning PHP5</title> 15 <author>David</author> 16 <publisher>White Water Press</publisher> 17 <price>29.90</price> 18 </book> 19 <book> 20 <title>Learning XML</title> 21 <author>Jeffson</author> 22 <publisher>White Water Press</publisher> 23 <price>50.79</price> 24 </book> 25 <books>
【代码解析】在这个XML文档中读者还可以看到其他一些符号,这些符号用来指定元素在XML出现的次数,如<!ELEMENT books(book)*>,这里的*表示<books>元素必须包含0个或多个book元素。星号表示这一项可以出现任意次,包括零次。表17-1列举了DTD中可以使用的一些符号及其解释。
表17-1 DTD中使用的特殊字符及其含义解释
这些符号的使用都类似于正则表达式,例如<!ELEMENT addressbook(address+)>,表示<addressbook>元素包含一个或多个<address>元素。可以有任意多的<address>元素,但必须至少有一个。加号表示这一项可出现任意次,但至少出现一次。
使用DTD也可以定义属性。在DTD中定义属性时,格式如下。
<!ATTLIST 元素名 (属性名 属性类型 默认值)*>
使用DTD可以完成的对属性的定义功能如下所述。
·定义哪些属性是必需的
·定义属性的默认值
·列出给定属性的所有有效值
如下是一个使用DTD定义属性的示例代码。
<!ELEMENT city (#PCDATA)> <!ATTLIST city province CDATA #REQUIRED>
这段示例XML代码定义了<city>元素,同时使用关键字ATTLIST声明元素的属性。属性列表中的名称city告知解析器这些属性是为元素<city>定义的。名称province是属性的名称,关键字CDATA和#REQUIRED告诉XML解析器province属性包含文本并且是必需的。如果是可选的,可以使用CDATA#IMPLIED。
XML中,关于DTD的内容是相当丰富的,本书只是略微介绍了DTD的一些基本概念和基础用法,更深更多的内容并没有涉及,有兴趣的读者可以参考有关XML的专门文献进行学习。
共有条评论 网友评论