第1章 XML
本章要点
● 了解XML的起源
● 弄清楚XML与HTML的区别
● 学会使用XMLSpy
● 了解XML的物理结构
● 掌握XML的逻辑结构
● 学会编写格式良好的XML文档
XML对我们来说已不再陌生,其相关概念和知识在网络上随处可见,有关XML的应用也越来越多。本章的目的是帮助读者快速了解和掌握XML,为后面章节的学习打下基础。
1.1 XML的起源
XML的全称是Extensible Markup Language,意思是可扩展的标记语言,它是标准通用标记语言(Standard Generalized Markup Language,SGML)的一个子集。那SGML又是什么呢?
在20世纪80年代早期,IBM提出在各文档之间共享一些相似的属性,例如字体大小和版面。IBM设计了一种文档系统,通过在文档中添加标记,来标识文档中的各种元素,IBM把这种标识语言称做通用标记语言(Generalized Markup Language,GML)。经过若干年的发展,1984年国际标准化组织(ISO)开始对此提案进行讨论,并于1986年正式发布了为生成标准化文档而定义的标记语言标准(ISO 8879),称为新的语言SGML,即标准通用标记语言。
SGML功能非常强大,是可以定义标记语言的元语言,然而由于SGML过于复杂,不适合在Web上应用,因此W3C组织在1996年便开始设计一种可扩展的标记语言,以便能将SGML的丰富功能与HTML的易用性结合到Web应用中。1998年2月10日,W3C发布了XML 1.0标准,其目的是为了在Web上能以现有的超文本标记语言(HTML)的使用方式提供、接收和处理通用的SGML。XML是SGML的一个简化子集,它以一种开放的、自我描述的方式定义了数据结构。在描述数据内容的同时能突出对结构的描述,从而体现出数据与数据之间的关系。
本书介绍的XML主要遵循W3C于2008年11月26日发布的XML 1.0推荐标准的第五版,读者可以在http://www.w3.org/TR/REC-xml/了解到此标准的详细内容。
W3C组织于2004年2月4日,发布了XML 1.1的推荐标准,并于2006年8月16日发布了XML 1.1推荐标准的第二版,这是最新的XML版本,不过由于目前大多数的应用还是基于XML 1.0的推荐标准,因此本书也将遵照XML 1.0规范来讲述。如果读者想要了解XML 1.1规范的内容,可以参看网址:http://www.w3.org/TR/2006/REC-xml11-20060816/。
1.2 W3C介绍
W3C是万维网联盟(World Wide Web Consortium)英文的缩写,成立于1994年10月,它以开放论坛的方式来促进开发互通技术(包括规格、指南、软件和工具),以激发网络的全部潜能。万维网联盟(W3C)的会员包括软件开发商、内容提供商、企业用户、通信公司、研究机构、研究实验室、标准化团体,以及政府,会员中的一些知名IT企业包括:IBM、Microsoft、America Online、Apple、Adobe、Macromedia、Sun Microsystems等。
W3C自成立以来,已发布了100多份Web技术规范,领导着Web技术向前发展。
W3C认为自身不是官方组织,因此将它正式发布的规范称为推荐(建议)标准,意思是进一步标准化的建议,但是由于该组织自身的权威性往往成为事实上的标准。一项技术要成为W3C的推荐标准,需要经过以下7个步骤。
(1)W3C收到提交(W3C Submissions)
任何W3C的成员都可以向联盟提交希望成为Web标准的某项建议。如果建议的内容在W3C的工作范围内,W3C将决定是否要对此开展工作。
(2)W3C发布注释(W3C Notes)
通常,一项对W3C的提交会成为一份注释。注释作为一份公共的文档,是对建议的描述。
注释仅供讨论使用。一项注释的发布,并不表示W3C对其认可了。注释的内容由提交此注释的会员来编辑,而不是W3C。注释可以在发布后随时被更新、替换或废弃。注释的发布,并不表示W3C已经开始任何与注释相关的工作。
(3)W3C成立工作组(W3C Working Groups)
当一项提交被W3C认可之后,就成立由成员和一些对此感兴趣的团体参加的工作组。通常情况下,工作组将定义一个时间表,并发布一个提议标准的工作草案,描述当前的工作进展。
(4)W3C发布工作草案(W3C Working Drafts)
W3C通常会在其网站上(http://www.w3.org)发布工作草案,以及一个公众讨论的邀请。工作草案会说明当前的工作进展。由于工作草案的内容可随时被更新、替换或废弃,所以不应把它作为工作的依据。
(5)W3C发布候选推荐标准(W3C Candidate Recommendations)
当规范比较复杂时,可能需要成员和软件提供商花费更多的时间来试用或测试。有时候,这些规范以候选推荐标准的形式发布。它与工作草案一样都是进展中的工作文件,所以不应把它作为工作的依据。该文档随时可以被更新、替换或废弃。
(6)W3C发布提议的推荐标准
提议的推荐标准的发布标志着工作组的工作到了最后阶段。提议的推荐标准仍然是一个进展中的工作文件,仍然可以被更新、替换或废弃。虽然提议的推荐标准还没有被W3C正式认可,但是它在内容和时间上离最终的推荐标准已经非常接近了。
(7)W3C发布推荐标准
推荐标准经过W3C的成员审阅,并由W3C的主任加盖正式批准图章,而最终成为规范。W3C的推荐标准是一个稳定的文档,可以作为工作中的参考资料。
1.3 关于XML的两个问题
1.XML是HTML的扩展吗
HTML的全称是Hypertext Markup Language(超文本标记语言),而XML的全称是eXtensible Markup Language(可扩展的标记语言),这很容易让人联想到XML是通过增加新标记来扩展HTML的一种标记语言。实际上HTML和XML在标记语言中处于不同的层次。
下面我们通过HTML文档和XML文档的对比(分别如例1-1和例1-2所示),来弄清楚XML的一些概念。
例1-1 HelloWorld.html
<html> <head> <title>这是一个欢迎的例子</title> </head> <body> 你好!欢迎你! </body> </html>
例1-2 HeDlloWorld.xml
<?xml version="1.0" encoding="GB2312"?> <欢迎词> <标题>这是一个欢迎的例子</标题> <内容>你好!欢迎你!</内容> </欢迎词>
从上面的两个例子,我们可以看出:
① 在编写HTML文档时,所有的标记都已经固定下来(如<html>、<body>等),我们不能去创造新的标记;而在编写XML文档时,我们可以任意地创建新的标记,包括中文的标记(如<欢迎词>、<内容>等)。所以说XML是可扩展的标记语言。
② 在编写XML文档时,没有一套标准的标记供我们选择使用,需要我们自己去创建标记,所以我们说XML是创建标记语言的元语言。
提示
XML在设计之初,就考虑到了国际化的问题,同HTML 4.01一样,XML也是基于ISO/IEC 10646字符集标准中定义的通用字符集(Universal Character Set,UCS),等价于Unicode 2.0。
2.SGML、HTML和XML之间是什么关系
SGML是一种在Web发明之前就早已存在的使用标记来描述文档资料的通用语言。它是一种定义标记语言的元语言。HTML和XML都是从SGML发展而来的标记语言,因此,它们有一些共同点,如相似的语法和标记的使用。不过HTML是在SGML定义下的一个描述性的语言,只是SGML的一个应用,其DTD (参见第2章)作为标准被固定下来,而XML是SGML的一个简化版本,是SGML的一个子集,严格意义上来说,XML仍然是SGML。
HTML不能用来定义新的应用,而XML可以,例如RDF和CDF都是使用XML定义的应用。事实上, XML和SGML是兼容的,但又没有SGML那么复杂,它被设计用于有限带宽的网络,如Internet。XML规范的制定者之一Tim Bray说,“XML的设计出发点是取SGML的优点,去除复杂的部分,使其保持轻巧,可以在Web上工作”。
下面我们用一个比喻来描述它们三者之间的关系。假如我们制定了一套设计图形元素的规则,称为SGML。现在为了规范建筑行业建筑图的绘制,需要使用一套固定的图形元素,于是我们根据SGML这种设计图形元素的规则设计了一套专门用于绘制建筑图的图形元素,那么这套图形元素就称为HTML。然而由于SGML过于复杂,不利于在其他行业推广,因此我们对SGML进行了简化,重新制定了一套设计图形元素的规则,这就是XML。由于XML是SGML的一个子集,因此它也可以用来设计图形元素。
HTML、SGML和XML将继续用于其适合的地方,它们中的任何一个都不会使其他一个废弃。对于像新闻、网络日记、论坛留言等大部分短期的数据,HTML仍是在Web上快速发布数据的最简单的方法。如果数据要长期使用,并且需要更多的一些结构,我们更推荐使用XML。不同于HTML和XML,SGML可能永远不会在Internet上被广泛接受,因为它不是为某个网络协议而设计的,也从来没有为某个网络协议的需求而优化过。对于高端的、复杂结构的发布应用,SGML将继续使用。
1.4 XML与HTML的比较
通过XML与HTML的比较,我们能够更好地理解和掌握XML的优点。
1.4.1 XML将数据与显示分开
我们看附录中的一个例子。
例1-3 SecondPage5.htm
<html> <head> <title>静夜思</title> </head> <body> <center> <h2><font color="red">静夜思</font></h2> <b>作者:李白</b> <hr color="blue"> <p> <b><i><font size=3 color="green">床前明月光,疑是地上霜。<br> 举头望明月,低头思故乡。</font></i></b> </center> </body> </html>
在上面的这个HTML文档中,“静夜思;作者:李白;床前明月光,疑是地上霜。举头望明月,低头思故乡。”这些是要显示的数据,<center>表示让内容居中显示,<h2>表示2号标题,<b>表示以粗体显示,<i>表示以斜体显示。
可以看到,HTML文档将数据,页面的排版,以及页面的表现形式混合在了一起,如果要增加新的数据,相应地就要调整数据的排版与显示方式。当我们从其他的地方(例如,数据库、文本文件)得到数据后,一旦放入HTML文档中,整个数据就会被打乱,数据和HTML标记混合在了一起,数据本身就变得无法辨析了。另一方面,随着电子商务等网络应用的流行,不同系统、不同平台、不同软件的信息交换日益频繁,而HTML本身的这些限制,导致了HTML在日益广泛的Web应用中,显得捉襟见肘,为此,就有了XML的产生。
我们将例1-3中的HTML文档中的数据部分改为用XML文档来表示,如例1-4所示。
例1-4 SecondPage5.xml
<?xml version="1.0" encoding="GB2312"?> <poem> <title>静夜思</title> <author>李白</author> <content> <line>床前明月光</line> <line>疑是地上霜</line> <line>举头望明月</line> <line>低头思故乡</line> </content> </poem>
在这个文档中,我们用<title>(此处的<title>是我们自己创建的标记)指明标题是“静夜思”,用<author>表明作者是“李白”,而内容是“床前明月光,疑是地上霜。举头望明月,低头思故乡”这四句诗。那么这个XML文档将如何显示呢?从文档中我们看不出这些数据将如何显示,这是因为:XML文档不能描述页面的排版和表现形式,它只是用于描述数据和数据的结构。也就是说,XML将数据和显示分开了,我们可以为这些数据设计不同的排版和表现形式,而数据本身不需要做任何的修改。
采用XML来表示数据,我们能够很容易地读懂XML文档,而计算机也能够很好地进行识别和处理。XML表示数据的方式真正做到了独立于应用系统,并且数据能够重用,一份数据可以应用于不同的场合。有时候,XML文档也被看作是文档的数据库化和数据的文档化。
1.4.2 XML对文档的格式要求更加严格
由于HTML文档格式非常松散,导致了HTML文档解析的复杂性,也造成了浏览器兼容的问题,所以XML从一开始,就对文档的格式制定了非常严格的标准,凡是符合这一标准的XML文档就是格式良好的XML文档(Well-Formed XML Documents)。
(1)开始标签必须要有一个配套的结束标签
在HTML文档中,可以直接使用<p>、<tr>、<td>等标签,而不用加结束标签,在XML中,开始标签和结束标签必须配套,也就是必须写成<p>…</p>、<tr>…</tr>或<td>…</td>。
(2)空元素标签必须被关闭
在HTML文档中,可以使用<br>、<hr>、<img src="logo.gif" width="197" height= "81">等单标签,而在XML中,空元素标签必须被关闭。空元素标签采用斜杠(/)来关闭,例如:<br/>、<hr/>、<img src="logo.gif"width="197" height= "81"/>。
(3)所有的标签都区分大小写
在HTML文档中,标签是不区分大小写的,<tr>和</TR>是tr元素的开始标签和结束标签,但是在XML中,<tr>和<TR>是两个不同的标签,开始标签和结束标签的大小写形式必须一致。
(4)所有的标签都必须合理嵌套
在HTML文档中,<b><i>…</b></i>是允许的,但是在XML中,这是错误的。在XML中,所有的标签都要成对出现,合理嵌套,正确的形式是:<b><i>…</i></b>。
(5)所有标签的属性值必须用双引号(" ")或单引号(' ')括起来
在HTML文档中,属性值可以加引号,也可以不加,例如:<hr color="blue">和<hr color=blue>都是合法的。在XML文档中,即使是数字字符,也必须加双引号或单引号(' '),例如:<student name="zhangsan"age='18'/>。
注意
在说明HTML和XML的区别时,为了进行对比,我们使用了相同名字的标签,但要注意的是XML并没有固定的标签,这些标签在XML中可以是完全不同的含义。
1.4.3 XML有且只能有一个根元素
在HTML中,可以有多个根元素,例如:
<table> … </table> <table> … </table>
但是在XML中,有且只能有一个根元素,例如:
<table> ... </table>
1.5 XML的编辑工具
工欲善其事,必先利其器。要编写XML文档时,首先就要有一个适合自己的XML编辑工具。在这里,我们介绍几种编辑工具。
(1)Notepad
Notepad即我们通常所说的记事本,这是Windows自带的文本编辑工具。XML文档本身是纯文本格式,所以可以直接使用Notepad作为编辑工具,这也是最方便得到的编辑工具。它的缺点就是文本只有一种颜色,不容易区分标签和数据,编写的效率太低。另外,Notepad也没有提供检验XML文档格式是否正确的功能。Notepad如图1-1所示。
图1-1 Notepad
(2)UltraEdit
这是一款功能强大的编辑器,不但可以编辑文本文件,还可以编辑二进制文件。UltraEdit可同时编辑多个文件,并针对不同类型的源文件,提供了语法高亮显示的功能。UltraEdit如图1-2所示。
图1-2 UltraEdit
读者可以在http://www.google.com上搜索UltraEdit,就能找到这个编辑工具。
(3)Stylus Studio
Stylus Studio是商业的XML集成开发环境,它包含了功能强大的XML编辑器、XSLT和XQuery调试器,以及其他许多XML工具,可以加快XML的开发速度。
最新的Stylus Studio X14支持XSTL 3.0、XPATH 3.0和XQuery 3.0,它提供了如下的三个版本:
● Stylus Studio® X14 XML Enterprise Suite
● Stylus Studio® X14 XML Professional Suite
● Stylus Studio® X14 XML Home Edition
要下载Stylus Studio的试用版本,可以登录网址:http://www.stylusstudio.com/,如图1-3所示。
图1-3 Stylus网站首页
单击图1-3中小手光标所指向的链接,进入Stylus Studio X14的下载页面,如图1-4所示。
图1-4 Stylus Studio X14的下载页面
选择你想试用的版本进行下载。读者也可以通过搜索引擎来下载该软件。
(4)XMLSpy
XMLSpy是Altova公司出品的工业标准的XML集成开发环境。它是一个集成了编辑、检验、预览等多项功能的商业性XML开发软件,功能非常强大,支持XML文档所见即所得的编辑方式、支持Unicode、多字符集,支持格式良好的和有效的XML文档,支持XML Schema,同时提供了强有力的样式表设计。XMLSpy也包含了XSLT和XQuery的调试器,以帮助你更好地开发XML应用。此外,XMLSpy还提供了Eclipse插件,以方便你在Eclipse中使用XMLSpy的功能。
读者可以在http://www.altova.com/上下载XMLSpy的试用版,如图1-5所示。
图1-5 Altova公司网站首页
在左边单击小手光标所指向的“xmlspy”链接,进入XMLSpy的说明页面,如图1-6所示。单击小手光标所指向的“Click here”链接,进入XMLSpy的下载页面,如图1-7所示
图1-6 XMLSpy的说明页面
图1-7 XMLSpy的下载页面
选择你要使用的语言(笔者选择的是Chinese),并根据你所使用的操作系统(32位还是64位)来选择对应的版本(笔者机器使用的是32位XP系统,所以选择的是32-bit version),选择完毕后,单击小手图标指向的链接开始下载。读者也可以通过搜索引擎来下载该软件。
本书使用的是XMLSpy 2012 sp1企业版,软件界面如图1-8所示。
图1-8 XMLSpy 2012 sp1企业版的界面
1.6 XML文档
1.6.1 XML文档的结构
每一个XML文档都有一个逻辑结构和一个物理结构。
逻辑上而言,文档由声明、元素、注释、字符引用和处理指令组成,在文档中,所有这些都是通过显式的标记(markup)来指明的。
XML标记(markup)包括开始标签(tag)、结束标签、空元素标签、实体引用、字符引用、注释、CDATA段定界符、文档类型声明、处理指令、XML声明、文本声明及任何在文档实体顶层的空白(在文档元素之外,且不在任何其他的标记内部)。其他所有非标记的文本组成文档的字符数据。XML文档各部分的标记如图1-9所示。
图1-9 XML文档各个组成部分的标记
XML文档在逻辑上主要由以下5个部分组成:
● XML声明
● 文档类型声明
● 元素
● 注释
● 处理指令
物理上而言,文档由称为实体(entities)的存储单元组成,实体都具有内容并且都通过实体的名字进行标识(文档实体和外部DTD子集除外)。实体可以是一段文本、一个文件、一个数据库记录或其他包含数据的项目。一个实体可以引用其他的实体,从而将它们包含在文档中。文档开始于“根(root)”或文档实体(document entity)。格式良好的XML文档形成了一种层次树结构,而这个树的根就是文档实体,它作为XML处理器进行处理的起点,可以包含整个文档。与其他实体不同,文档实体没有名字,只是用于表示文档树的根。XML文档的根元素被称为文档元素(document element),它和在其外部出现的处理指令、注释等作为文档实体的子节点,而根元素本身和其内部的子元素也是一棵树。
实体可以包含已解析(parsed)的或未解析的(unparsed)数据。已解析的数据由字符组成,其中一些字符组成字符数据,另一些字符组成标记。已解析实体(parsed entity)的内容称为它的替换文本,这个文本被看成是文档整体的一部分。在XML处理器解析XML文档时,凡是文档中出现引用已解析实体的地方,都将被该实体的内容所替换。
未解析的实体(unparsed entity)是一种资源,它的内容可以是也可以不是文本,并且,如果是文本的话,可以不是XML文本。每一个未解析的实体都有一个相关联的用名字标识的记号(notation)。除了要求XML处理器能向应用程序提供可用的实体和记号的标识符之外,XML对未解析实体的内容不做任何限制。
已解析实体以实体引用的方式通过名字来调用;未解析实体通过ENTITY或ENTITIES属性中给出的名字来调用,如图1-10所示。
图1-10 已解析实体和未解析实体的调用
关于实体的更多内容请参看第2章的2.2.2节。
1.6.2 在XMLSpy中创建XML文档
要在XMLSpy中创建一个XML文档,可以单击菜单【文件】→【新建…】,在弹出的“Create new document”对话框中选择“xml Extensible Markup Language”,单击“确定”按钮,如图1-11所示。
图1-11 在XMLSpy中新建XML文档
在接下来的“新文件”对话框中单击“取消”按钮即可。之后,你就可以在XMLSpy的编辑窗口中开始编写XML文档了,如图1-12所示。
图1-12 在XMLSpy中编辑XML文档
1.6.3 XML声明
XML文档总是以一个XML声明开始,其中指明所用的XML版本、文档的编码、文档的独立性信息。其格式为:
<?xml版本信息[编码信息][文档独立性信息]?>
其中,括号([])中的部分表示可选信息。
(1)版本声明
<?xml version="1.0"?>
书写时以左尖括号(<)开始,后面紧跟一个问号(?),然后是XML保留的字符串名字“xml”,要注意的是在问号(?)左右两边不能有空格;接下来,指明所用的XML版本为“1.0”;然后以问号(?)和右尖括号(>)结束,在问号(?)和右尖括号(>)之间不能有空格。
有的读者可能对于在XML声明时加上版本号而感到不解,这是因为随着XML的发展,XML必然会进行修订或者扩充,XML工作组在制定新的或者改进XML标准时,会使用新的版本号,就像XML现在有两个版本,1.0和1.1,而不同的版本之间,其实现的细节也是不一样的。这样当一个支持1.0版本的XML处理器(读取XML文档并分析其结构的软件)在解析一个1.1版本的XML文档时,就可能会碰到一些不能识别的符号或语法,从而导致解析的结果不正确。通过在XML文档的开始处写上XML声明,XML处理器就可以根据声明来判断该文档所遵守的XML规范,如果遇到不支持的版本,就不用再解析处理,直接给出一个错误信息,如图1-13所示。
图1-13 IE 8.0解析1.1版本的XML文档出错
(2)文档编码声明
在XML声明中还可以加上文档编码信息,默认是UTF-8,如果要使用中文,可以在声明中加上encoding="GB2312",如下所示:
<?xml version="1.0" encoding="GB2312"?>
(3)独立文档声明
如果我们的文档不依赖于外部文档,在XML声明中,可以通过standalone="yes"来声明这个文档是独立的文档。如果文档依赖于外部文档,可以通过standalone="no"来声明。完整的XML声明如下所示:
<?xml version="1.0" encoding="GB2312" standalone="yes"?>
注意
XML声明必须位于文档的第一行,前面不能有任何字符。
1.6.4 文档类型声明
在一个XML文档中,你可以任意定制标签,但是当你将XML文档提交给别人使用时,他怎么才能知道你所提交的文档中元素与元素之间、元素与属性之间的关系,以及属性的取值是正确的呢?我们考虑这样一种情况,一家钢厂委托张三用XML文档来记录这家钢厂所有的钢材型号信息,张三首先确定了数据的组织结构,然后定制标签,用这些标签来描述数据。而另一家钢厂则委托李四用XML文档来记录自身生产的钢材型号信息,李四也制定了相应的数据存储结构和标签。假如这两家钢厂现在要交换钢材型号信息,结果却发现彼此信息的存储结构和XML标签不一样,同一种型号的钢材有两种表示方式,无法实现自动数据交换。出现这样的问题,主要是因为在这两家钢厂之间,没有一个规范来定义XML文档中元素和属性的规则及相互关系。我们可以用DTD(Document Type Definition,文档类型定义)来规范XML文档。
XML从SGML继承了用于定义语法规则的DTD机制,但DTD本身并不要求遵循XML规则,几乎所用的XML应用都是使用DTD来定义的。HTML就有一个标准的DTD文件,所以其组织结构和所有的标签都是固定的。DTD文件也是一个文本文件,通常用“.dtd”作为其扩展名。
通过文档类型声明,指出XML文档所用的DTD。文档类型声明有两种形式,一种是声明DTD在一个外部的文件中,例如:
<!DOCTYPE greeting SYSTEM "hello.dtd">
另一种是直接在XML文档中给出DTD,例如:
<?xml version="1.0" encoding="GB2312" standalone="yes"?> <!DOCTYPE greeting [ <!ELEMENT greeting (#PCDATA)> ]>
关于DTD的详细信息,请参见第2章。
1.6.5 元素
在XML中,元素由开始标签、元素内容和结束标签构成。空元素则由空元素标签构成。每一个元素有一个用名字标识的类型,同时它可以有一个属性说明集,每一个属性说明有一个名字和一个值。在给元素命名的时候要注意,以"xml"或其他任何匹配(('X'|'x') ('M'|'m') ('L'|'l'))的字符串开头的名字,被保留用于XML规范的当前版本或后续版本的标准化。另外,在给元素命名时,还需要遵守下列规范:
● 名称只能以字母、下画线(_)或者冒号(:)开头;
● 名称中可以包含字母、数字、下画线及其他在XML标准中允许的字符;
● 名称中不能包含空格;
● 名称中尽可能不要使用冒号(:),因为冒号在名称空间中被用于分隔名称空间前缀和本地部分,详细内容可参见第2章。
1.元素的形式
XML中的元素和HTML是类似的,也有4种形式。
空元素
<student/>
书写空元素时一定要加上斜杠(/)来关闭标签。另外要注意的是,虽然空元素在XML文档中是合法的,但是因为XML是用来表示数据的,而空元素没有任何数据,所以在XML文档中几乎不使用空元素。
带有属性的空元素
<student name="张三" age="18"/>
使用空元素时,可以通过属性来传递信息。同样地,不要忘了用斜杠(/)来关闭空元素标签。
带有内容的元素
<student> 这是一个学生的信息 <name>张三</name> <age>18</age> </student>
在<student>开始标签和</student>结束标签之间,就是元素的内容,包含了字符数据“这是一个学生的信息”,两个子元素name和age。这两个子元素的内容只包含了字符数据,student是它们的父元素。
带有内容和属性的元素
<student name="张三"> <age>18</age> </student>
student元素有一个属性name,其值为“张三”,还包含了一个子元素age,age元素包含了字符数据“18”。
提示
“元素”和“标签”这两个词具有不同的含义。元素是指开始标签、结束标签,以及两者之间的一切内容,包括属性、文本、注释及子元素。标签是一对尖括号(< >)和两者之间的内容,包括元素名和所有属性。例如: <font color ="blue">是一个标签,</font> 也是一个标签;而<font color="blue">Hello World</font>则是一个元素。
2.元素内容的构成
元素的内容可以包含子元素、字符数据、字符引用和实体引用、CDATA段。
(1)子元素
子元素本身也是元素,嵌套在上层元素之内。子元素是相对于父元素而言的,如果子元素还嵌套了其他元素,那么它同时也是父元素。我们看一个例子:
<students> <student> <name>张三</name> <age>18</age> </student> ... </students>
<student>是<students>的子元素,同时也是<name>和<age>的父元素,而<name>和<age>是<student>的子元素。
(2)字符数据
在一个元素的内容中,字符数据可以是不包括任何标记的起始定界符和CDATA段的结束定界符的任意字符串,也就是说在元素的内容中,字符数据不能有和号(&)和小于号(<),也不能有字符串“]]>”(见CDATA段)。在CDATA段中,字符数据可以是不包括CDATA段的结束定界符的任意字符串。下面,我们看几个例子。
<data>&</data>
错误,在元素的内容中,不能有和号(&)。
<data>/</data>
正确,斜杠(/)并不是标记的起始定界符。
<data>/></data>
正确,斜杠(/)与大于号(>)并不是标记的起始定界符。
<data><</data>
错误,小于号(<)是元素开始标签的起始定界符。
<data>]]></data>
错误,在元素的内容中,不能有CDATA段的结束定界符“]]>”。
(3)字符引用和预定义实体引用
在字符数据中,不能有和号(&)和小于号(<),因为未经处理的小于号(<)与和号(&)在XML文本中往往被解释为标记的起始定界符(例外的情况见CDATA段)。
那么如果在数据中需要出现和号(&)和小于号(<),我们应该怎么做呢?在XML中,提供了5个预定义的实体引用,分别引用XML文档中的5个特殊字符:小于号(<)、大于号(>)、双引号(")、单引号(')、和号(&)。这5个特殊字符也可以通过字符引用的方式去引用。
字符引用和预定义实体引用都是以一个和号(&)开始并以一个分号(;)结束。如果用的是字符引用,需要在和号(&)之后加上一个井号(#),之后是所需字符的十进制代码或十六进制代码(ISO/IEC 10646字符集中字符的编码)。如果用的是预定义实体引用,在和号(&)之后写上字符的助记符。表1-1列出了这5个特殊字符的字符引用和预定义实体引用。
表1-1 特殊字符的字符引用和预定义实体引用
在XML文档中,有些地方不允许出现这5个特殊字符中的某一个或几个,这时我们就可以通过字符引用或预定义实体引用的方式来输入。
提示
字符引用不只是可以引用这5个特殊字符,只要是在ISO/IEC 10646字符集中的字符,都可以通过字符引用的方式去引用。
关于实体引用更多的内容请参见第2章的2.2.2节。
(4)CDATA段
CDATA段中包含的都是纯字符数据,在字符数据可以出现的任何地方都可以使用CDATA段。CDATA段主要用于需要将整个文本解释为字符数据而不是标记的情况下。CDATA段中的内容不被XML处理器所解析,所以可以在其中包含任意的字符。例如,在XML文档中,我需要包含Java代码,而Java代码中可能存在着小于号(<)、大于号(>)、双引号(")、单引号(')、和号(&)这些特殊字符,这个时候,CDATA段就派上用场了。
CDATA段以字符串“<![CDATA[”开始,以字符串“]]>”结束。我们看一个元素内容包含Java代码的例子,如例1-5所示。
例1-5 java.xml
<?xml version="1.0"?> <java> <![CDATA[ if(a>b && c<b) max=a; ]]> </java>
在浏览器中的显示效果如图1-14所示。
图1-14 元素的内容中包含Java代码
下面我们再看一个例子,如例1-6所示。
<?xml version="1.0"?> <java> <![CDATA[ if(array[num[i]]>10) Fun(); ]]> </java>
读者可以仔细观察一下这个文档,看看有没有错误。javaerr.xml在浏览器中的显示效果如图1-15所示。
图1-15 CDATA段中包含了非法的字符序列
注意IE提示的错误信息,“元素内容中不允许使用文字字符串 ']]>'”,因为字符串“]]>”是CDATA段的结束定界符,在我们的Java代码中,碰巧有字符串“]]>”,所以IE在解析这个文档的时候,就报错了。要解决这个问题,就要在“]]”与“>”之间插入空格,或者把字符串“]]>”分别放到两个CDATA段中。
有的读者可能会想,前面刚讲过,特殊字符可以采用字符引用或预定义实体引用的方式去引用,那么为什么还要使用CDATA段呢?
如果字符数据中只有少量的特殊字符,我们可以采用字符引用和预定义实体引用的方式,但是如果字符数据中包含有较多的特殊字符,例如,用XML来写HTML的介绍,那么大量的特殊字符转换为字符引用或预定义实体引用,将是非常大的工作量(当然,一些工具软件可以帮助完成这种转换),即使转换完成也将导致XML文档的可读性变差。所以遇到这种情况,我们应该使用CDATA段来输出包含大量特殊字符的字符数据。
1.6.6 注释
在XML文档中,注释可以出现在文档中其他标记之外的任何位置,另外,它们还可以在文档类型声明中语法(grammar)允许的地方出现。XML的注释和HTML的注释类似,都是以“<!--”开始,以“-->”结束。位于“<!--”和“-->”之间的数据将被XML处理器忽略。例如:<!--This is a comment-->。
注释用于对文档中的内容起一个说明作用。使用注释时,要注意以下5点。
① 注释不能出现在XML声明之前,XML声明必须是文档最前面的部分。下面的情况是不允许的。
<!--Author:sunxin--> <!--Date:18-01-2005 --> <?xml version="1.0"?>
例1-6 javaerr.xml
② 注释不能出现在标记中,下面的例子是非法的。
<greeting<!--Begin greet-->>Hello, world!</greeting>
③ 注释可以包围和隐藏标记,但要注意的是,在注释掉标记之后,要保证剩余的文本仍然是一个结构完整的XML文档。例如:
<?xml version="1.0"?> <greeting> <!-- <title>This is a greeting example</title> --> <content>Hello, world!</content> </greeting>
当我们将注释部分去掉的时候,文档结构仍然是完整的:
<?xml version="1.0"?> <greeting> <content>Hello, world!</content> </greeting>
④ 字符串“--”(双连字符)不能在注释中出现。下面的例子是非法的。
<!--This is a greet example--Hello, world-->
这意味着,我们在注释中书写程序代码的时候,不能出现类似于i--或--i这样的代码。
⑤ 在XML中,不允许注释以“--->”结尾。下面的例子是非法的。
<!--This is a greet example--->
1.6.7 处理指令
处理指令(Processing Instructions,PI)允许文档中包含由应用程序来处理的指令。在XML文档中,有可能会包含一些非XML格式的数据,这些数据XML处理器无法处理,我们就可以通过处理指令来通知其他应用程序来处理这些数据。虽然处理指令不是文档字符数据的一部分,但是XML处理器会将处理指令传递给应用程序。
处理指令(PI)的语法和XML声明类似,以<?开始,以?>结束。一个常见的使用样式表单的处理指令如下所示:
<?xml-stylesheet href="hello.css" type="text/css"?>
在开始标记<?后的第一个字符串“xml-stylesheet”,叫做处理指令的目标,它必须标识要用到的应用程序,要注意的是,对于其他的非W3C定义的处理指令不能以字符串“XML”和“xml”开头;其余的部分是传递给应用程序的字符数据。应用程序从处理指令中取得目标和数据,执行要求的动作。
处理指令的目标可以是要使用的程序的名字,或者是一个类似于xml-stylesheet这样的很多程序可以识别的通用标识符。不同的应用程序支持不同的处理指令,对于不认识的处理指令,大多数应用程序采取忽略的方式进行处理。
xml-stylesheet处理指令总是放在XML声明之后,第一个元素之前。其他的处理指令可以放在除标记的内部和XML声明之前的任何位置。
要注意,虽然XML声明和处理指令的语法形式相似,但XML声明并不是处理指令,XML处理程序对XML声明和处理指令采取的是不同的处理方式。
1.6.8 空白处理
在编辑XML文档时,我们常常使用空白(空格、制表符和空行)来分隔标记,以获得较好的可读性。然而,在交付的文档版本中,这些空白可能就不需要了,但有时候,又需要保留这些空白,例如,诗歌、程序代码中的空白。
XML处理器总是将文档中不是标记的所有字符都传递给应用程序,一个进行有效性验证的XML处理器会通知应用程序这些字符中的哪一些组成了出现在元素内容中的空白。
在XML文档中,可以在元素中使用一个特殊的属性xml:space,来通知应用程序保留此元素中的空白。在有效的文档中(关于有效的文档,请参见第2章),这个属性和其他任何属性一样,在使用时必须声明。xml:space属性必须被声明为枚举(Enumerated)类型,它的值必须是“default”和“preserve”两者之一,也可以两个都取。例如:
<!ATTLIST poem xml:space (default|preserve) 'preserve'> <!ATTLIST pre xml:space (preserve) #FIXED 'preserve'>
值“default”表示对此元素使用应用程序的默认空白处理模式,值“preserve”指示应用程序保留所有的空白。如果一个元素使用了xml:space属性,将适用于该元素内容中的所有元素,除非被另一个xml:space属性的实例所覆盖。
XML文档的根元素被认为对应用程序的空白处理方式不作要求,除非它给xml:space属性赋了值或将该属性声明为有一个默认值(关于属性声明,请参见第2章的2.2.3节)。
1.6.9 行尾处理
XML数据经常以文本的方式保存在计算机文件中,以行来分隔。然而,不同的计算机系统采用的行分隔符是不同的。在XML空白字符中,有两个是标准的ASCII码行尾控制字符:回车(CR,#xA)和换行(LF,#xD)。在Windows平台下,采用#xD#xA的组合作为行分隔符,而Linux、UNIX系统则采用#xA作为行分隔符,在Mac OS下,采用#xD作为行分隔符。
为了简化应用程序的工作,XML处理器在解析XML文档前,要将所有的两字符序列#xD#xA,以及单独的#xD字符转换成单个的#xA字符。
1.6.10 语言标识
在文档处理中,标识出其内容所使用的自然或人工语言常常是很有用的。可以在文档中插入一个特殊的属性xml:lang,来指出XML文档中任何元素的内容和属性的值所使用的语言。在有效的文档中,这个属性和其他任何属性一样,在使用时必须声明(参见第2章的2.2.3节)。xml:lang属性的值是在IETF RFC 3066 (Tags for the Identification of Languages)或它的后继版本中定义的语言标识符,另外,也可以为其指定空字符串。例如:
<p xml:lang="en">The quick brown fox jumps over the lazy dog.</p> <p xml:lang="en-GB">What colour is it?</p> <p xml:lang="en-US">What color is it?</p> <sp who="Faust" desc='leise' xml:lang="de"> <l>Habe nun, ach! Philosophie,</l> <l>Juristerei, und Medizin</l> <l>und leider auch Theologie</l> <l>durchaus studiert mit heißem Bemüh'n.</l> </sp>
属性xml:lang所指定的语言适用于它所在元素的所有属性及元素的内容,除非被该元素内容中的另一个元素的xml:lang的实例所覆盖。我们可以为一个子元素的xml:lang属性赋一个空值,来覆盖其父元素上的xml:lang属性设置。在该子元素内,将没有可用的语言信息,就好像在它自身及其祖先元素(父元素、父元素的父元素,等等)上没有指定xml:lang属性一样。
xml:lang的一个简单声明可以采用如下形式:
xml:lang NMTOKEN #IMPLIED
不过,如果合适的话,也可以给出指定的默认值。在一本供英国学生使用的法文诗歌集中,注解(gloss)和笔记(note)使用英语,xml:lang属性可以这样声明:
<!ATTLIST poem xml:lang NMTOKEN 'fr'> <!ATTLIST gloss xml:lang NMTOKEN 'en'> <!ATTLIST note xml:lang NMTOKEN 'en'>
1.7 格式良好的XML
如果一个XML文档有且只有一个根元素,符合XML元素的嵌套规则,满足XML规范中定义的所有格式正确性的约束,并且在文档中直接或间接引用的每一个已分析实体都是格式正确的,我们称这个文档是一个格式良好(well-formed)的XML文档。
为什么格式良好的XML是如此重要呢?主要是因为:
● 可以创建没有DTD的XML文档,便于利用XML文档做数据的交换;
● XML的处理器可以做得很小很快,从而应用于手持设备,例如,PDA、手机等存储容量较小的设备。
我们在编写完一个XML文档后,可以通过IE浏览器或XMLSpy进行格式良好的检查。利用IE检查,只需要用IE浏览待检查的XML文档,如果格式有问题,IE会给出错误提示信息。微软的产品兼容性一向比较好,不过这种“兼容性”应用到XML的检查上,却容易给用户造成不必要的麻烦,IE在XML格式是否良好的检查上设定得比较宽松,所以我们在判断文档格式是否良好时,最好用别的工具,例如XMLSpy来做检查。举个例子,如果你在XML声明前面加一些空格、回车等空白符,IE不会报错,而XMLSpy会给出错误提示信息:“This file is not well-formed: Processing Instruction Name (may not be 'xml') expected.”。在XMLSpy中,可用鼠标单击黄色的对号或按下功能键F7,对文档进行格式良好的检查,如图1-16所示。
图1-16 在XMLSpy中检查文档是否是格式良好的
1.8 小结
本章首先介绍了XML的起源,并澄清了初学者关于XML的两个问题。接着通过XML与HTML的比较,阐述了XML的作用,它主要用于表示数据,其对格式的要求比HTML更加严格。
本章随后详细介绍了XML文档的组成结构,每一个XML文档都有一个逻辑结构和一个物理结构。XML文档的逻辑结构主要包括XML声明、文档类型声明、元素、注释和处理指令几部分。物理上而言,文档由称为实体(entities)的存储单元组成。
如果一个文档符合XML规范中定义的所有格式正确性的约束,并且在文档中直接或间接引用的每一个已分析实体都是格式正确的,我们称这个文档是一个格式良好(well-formed)的XML文档。