xml
你现在应该知道XML只说明数据的结构而并不关心数据是如何具体描述的、数据是否正确。XML文档的强制性结构化需求是通过DTD(文档类型说明)来实现的。那就是本系列文章中先前讲述的主题。在本文里,我们概要介绍DTD所存在的缺点,讨论新型的更为强大的标准XML Schema。
其他文章
以下是本系列的另两篇文章:
XML的基本语法
DTD文档格式
DTD的麻烦
使用DTD虽然在指定许可的元素、需要的元素以及给定XML文档中如何组织元素等方面给我们以较大的方便,但是,一旦你想针对特定元素施加数据类型就会遇到麻烦了。DTD规范严格地定义了结构,但只支持相对功能较弱的内容类型规范,而对强制性结构化却无计可施,比如名为Date 的数据如何规定它必须包含有效值呢?
这就要指望XML Schema了,XML Schema目前作为建议已经于2001年提交给了W3C ,这意味着它最终将成为一般用途的建议标准。假如你对此感兴趣,你不妨到W3C网站找些官方文档和内容简介之类的材料来看看。注意,其他schema定义也是有的,包括日本的标准RELAX 和微软公司的XDR。可是,XML Schema是唯一受到W3C成为的建议标准,所以我在这篇文章中只对它进行阐述。
XML Schema不仅可以让你定义XML文档的结构而且还允许你约束文档的内容,这就不同于DTD了。另外,一个 XML Schema自身就是一个XML文档,其基于标签的语法比DTD中的特殊字符要清楚多了。
Schema概述
XML Schema是用一套预先规定的XML元素和属性创建的,这些元素和属性定义了文档的结构和内容模式。相应的一套精巧的规则(这些规则却很有意思的用DTD来表示)指定了每个Schema元素或者属性的合法用途。如果违反这些规则解析器就会拒绝解析你的Schema以及任何同它相联系的文档。
现在让就让我们来看看清单A中显示的XML Schema示例,该例对我们以前在清单B中用到的图书目录进行了说明。清单B有了点小改动:作为根元素的catalog现在有了两个新属性,它们通过清单A中的catalog schema与之关联。
你再看catalog schema,很快你就会注意到它包含了标准的XML头<?xml version = "1.0"?>,这表示schema自己就是一个XML文档。而任何schema的根元素都必须是schema,它有一个或者多个说明自己的属性。在这种情况下,schema的namespace定义属性(xmlns)会定义名称空间为xs,它将用作文档中所有元素的根名称空间。
什么是名称空间
XML把名称空间定义为包装XML元素在一起供以后重用的方式。为了使用XML文档的名称空间中定义的元素,你必须通过xmlns属性声明你希望采用名称空间。你还必须为该名称空间定义快捷方式的前缀(例如xs:)作为你文档中的根元素,从而使得名称空间在文档中都可用。前缀是用于文档的任何导入名称空间的元素的标识符。这一过程就如同在Visual Basic中给库加索引或者导入模块;C++、Java或者.NET下的名称空间也具有同样的含义。
我们的schema示例中接下来的元素是annotation,它的作用是代表同其父元素有关的文档。annotation可以包含两个子元素之一,或者是documentation或者是appinfo,或者两者都包含进去。前者用于可读的文档,而后者则用来保存供应用程序处理的指令。
接下来我们定义了两个主要的元素(根元素catalog及其子元素book),它们用在书目文档内,后者采用了两个element元素。这些元素都包含了定义名字的属性和各个元素准许的内容。在这种情况下,catalog元素被定义为catalogtype类型,而book元素则被定义为elementtype类型;这两种类型以后还要在schema文档中被定义。
什么是类型?
我已经说过了,XML Schema可以让你把XML文档中的元素声明为特定的类型,准许解析器检查文档的内容及其结构。XML Schem定义了两种主要的数据类型:预定义简单类型和复杂类型。这两种数据类型之间的主要区别是复杂类型可以象数据一样包含其他元素而简单类型则只能包含数据。简单类型给予了XML Schema低级类型检查能力,允许你把元素定义为图A中的任何类型之一。
图A
简单类型
定义
string
字符串数据。
boolean
二元类型的True或者False。
date
历法日期,格式是CCYY-MM-DD。
dateTime
历法日期和时间。
time
24小时格式的时间可根据时区调节。
decimal
任意精度和位数的十进制数。
integer
整数
float
标准的32位浮点数。
XML Schema预定义简单类型
你也可以定义自己的简单类型。为了更深入地了解各种XML Schema数据类型,请参看W3C网站上的“XML Schema Part 2: DataTypes”。
复杂类型由complexType元素定义,它通常至少拥有一个name属性,用在声明其他元素时索引类型,除非它位于某一元素之内(参见下一节)。所有的复杂类型都会包含一个内容定义类型,其主要功能是定义类型能包含的内容模式。某些可用的内容模式请见图B。
图B
复杂类型
定义
sequence
在其定义范围之内的所有元素都必须按顺序出现,范围由minOccurs和 maxOccurs指定。
choice
其范围内有且只有一个元素必须出现。
any
定义的任何元素都必须出现。
simpleContent
这种复杂类型只包含了非嵌套元素。可以通过包含扩展元素的方式扩展先前定义的简单类型。
complexContent
这种复杂类型只能包含其他元素。可以通过包含扩展元素的方式扩展先前定义的复杂类型。
attribute
这种复杂类型只能包含命名属性。
一些准许的XML Schema复杂类型
我们示例schema中的第一个complexType元素定义了booktype类型,你能从文档注释元素中看出,该类型给目录中单一的书建模型。Booktype包含一个sequence元素,通过它告诉解析器这种复杂类型的元素必须按照同样准确的顺序包含出现在sequence标签内出现的所有元素。就booktype而言,元素author、title、genre、price和publish_date都必须出现在 booktype元素之内。
Description又是怎么一回事呢?它出现在sequence元素内,有没有这个必要呢?当然没有。description元素有一个minOccurs属性,它定义了复杂类型中元素可以出现的最小次数。在这种情况下,minOccurs的值是零,因此description是一个可选的元素。
author元素也是这样。它有一个maxOccurs属性,但却没有设值,意思是说author元素可以在sequence中出现无限次,显然,一本图书的作者至少有一个但却不一定只有一个。既没有minOccurs也没有maxOccurs属性的元素必须而且仅仅只能在sequence中出现一次,因此,booktype sequence中的所有其他元素都是必要的而且只能出现一次。
在我们的示例catalog schema中定义的第二个同时也是最后一个复杂类型是catalogtype复杂类型。它也是包含一个以上的sequence,你可以从无界的maxOccurs属性看出这一点。
深入解释
看你的背景知识有多少了,本文用到的示例schema的结构对你来说要不本该如何要不只会叫你发昏,对book和catalog元素不采用正规复杂类型声明来定义catalog schema也是可能的,清单C就是这样。注意,清单C中的complexType元素嵌套在了element元素之内,catalog的sequence元素的子元素具有一个ref属性通过它告诉解析器它有一个引用指向先前定义的book元素。
我曾经听到很多人这样问:“很好,如果是这样的话,那么你为什么要采用以上那些费工夫的办法呢?”很简单,我们绕来饶去只是为了说明XML Schema的重要一点:它是可扩展的。通过定义类型的方式你就可以在多个文档中重用它们,甚至还可以用不同的schema对其进行扩展,这就像你在开发应用程序的时候重用或者扩展抽象数据类型或对象是一个道理。
工具
到目前为止,你应该意识到XML Schema的语法并不简单。虽然可以用简单的文本编辑器手工创建schema,不过,这样做也许会叫你累得吐血。为了更好地利用它,你可以采用若干种XML工具,最近出现的一些工具甚至提供了创建XML Schema的图形界面。XML Spy和Cape Clear Studio都是具有XML Schema创建功能的全方位XML综合开发环境。dtd2xs是一种DTD-to-XML的Schema转换工具,它有两种形式:单独运行的应用程序和Java类。同DTD一样,标准的XML Schema定义非常多,你可以根据自己的需要在应用程序的开发中采用。
结论
XML Schema具有强制文档内容和结构的能力,它是XML世界中的一种不但重要而且强大的新标准。在这篇文章里,我仅仅浮光掠影地大致解释了其基本原理,但我希望这些阐述能给你打下一个继续前进的基础。接下来我们继续探讨DOM解析器。