作者:未知
目录
1.0 简介 (Introduction)
本文对怎样使用XML和数据库做了总体回顾,描述了以数据为中心和以文档文中心的文档的差异如何影响到在数据库中的应用,XML和关系型数据库的一般用法,以及什么是原生XML数据库和何时使用它。
2.0 XML是数据库吗?(Is XML a Database?)
在开始讨论XML和数据库之前,我们先回答许多人提过的问题:“XML是数据库吗?”
如果仅按数据库这个术语的本质来看,XML文件是数据库。即它是数据的集合。在许多方面看起来它和其他文件没什么区别 -- 无论如何,每个文件都含有某种类型的数据。作为一种“数据库”格式,XML有一些优势:例如,它是自描述的(所用的标记描述了数据的结构和类型,尽管缺乏语义),可交换的(portable)(Unicode),能够以树型或图形结构描述数据。同样它也有缺点,例如,它是冗余的,由于要对它进行解析和文本转换,所以数据访问速度较慢。
一个更有用的问题就是在宽松的意义上,XML及其周边技术是否可以算作“数据库” -- 即数据库管理系统(DBMS)。答案是“在某种程度上是(sort of)”。从正面来说,XML提供了许多数据库所具备的东西:存储(XML文档), 模式(DTD, XML schema语言), 查询语言(XQuery, XPath, XQL, XML-QL, QUILT等等),编程接口(SAX, DOM, JDOM)等等。从反面来说,它缺少一些真正的数据库所应具备的东西:高效的存储,索引,安全,事务和数据一致性,多用户访问,触发器,在多个文件中查询等等。
XML适合于用作所谓“数据库”的一个好例子就是 .ini文件 -- 它包含应用程序的配置信息。与其写一个处理以逗号分隔(comma-delimited)的文件的解析器,开发一种小型的XML语言并写一个解释它的SAX程序要容易的多。此外,XML允许使用嵌套的实体,而逗号分隔的文件(comma-delimited files)很难做到这点。然而,说它就是数据库还很勉强,因为它是线性读写的,而且仅用在程序开始和结束时。
比较适合于XML数据库的一些复杂的数据集就是个人通讯录(名字,电话号码,地址等),或用于描述浏览器书签以及用Napster偷来的MP3。然而,由于dBase和Access之类的数据库物美价廉,即使在这种情况下似乎也没有多少理由把XML文件作为数据库使用。XML的唯一真正好处就是数据的可交换性(portable),由于有越来越多的工具可以用来将数据库当作XML进行存取,这一点好处似乎也要打些折扣。
3.0 为什么要用数据库?(Why Use a Database?)
当你开始考虑XML和数据库的时候首先要回答这个问题:为什么你会先想到使用数据库?你是否想利用现有数据?是否想找个地方存储Web页面? 是否在电子商务中使用数据库,而XML在其中作为数据传输载体? 对这些问题的回答将会极大地影响你对数据库和中间件(如果有的话)的选择, 以及如何使用数据库。
例如,你有个电子商务的应用,将XML用作数据交换。那么你的数据最好有个高度规整的结构并且供非XML程序使用。还有,XML文档所用的某些东西如实体和编码对你来说可能并不重要 -- 总之,你感兴趣的是数据,而不是它在XML内如何存储。在这种情况下,你大概需要一个关系型数据库以及在XML和数据库之间转换数据的软件。如果你的应用程序是面向对象的,你甚至还需要一个在数据库或XML中存取这些对象的系统。
另一方面,假如你要从一些面向散文(prose-oriented)的XML文档建立一个网站。你不但要管理这个网站,还要提供一个途径让用户可以查找内容。你的文档看起来结构比较松散,其中的实体的使用对你来说可能更重要,因为它们是文档结构的重要部分。这种情况下,你也许需要一个原生XML数据库(native XML database)或内容管理系统(content management system)。这就使你可以保持文档的物理结构,支持文件级的事务处理,以及使用XML Query语言进行查询。
4.0 数据和文档 (Data versus Documents)
在选择数据库时最重要因素大概就是你想在数据库存储数据还是文档。例如,是简单地把XML当作数据库和(可能不支持XML)应用程序之间的数据转换工具,还是用于集成,就像XHTML和DocBook中的那样?通常这是个偏好,但是却非常重要,因为所有以数据为中心的(data-centric)文档有着许多相同的特性,所有以文档为中心的(document-centric)也有许多相同的特性。这会影响到XML在数据库中如何存储。下面两部分中我们就来考察这些特性。
(历史背景:我在xml-dev邮件列表上第一次听说data-centric和document-centric这些术语,不知道是谁发明的,但是我在1997的消息中发现有使用document-centric的,从1998年以后这两个术语都有使用。)
4.1 以数据为中心的文档 (Data-Centric Documents)
以数据为中心的文档就是将XML用作数据的传输载体,专门提供给机器消费,其实没有必要全部采用XML。也就是说,对于应用程序或数据库而言,(在某个时间段内)数据是否以XML文档的形式存储并不重要。以数据为中心的文档的例子有销售订单、航班时刻表、科研数据及股市汇率。
以数据为中心的文档的特点是结构相当规整,数据粒度精细(fine-grained data)(即最小的独立数据单位只存在于PCDATA元素或属性级别),很少或没有混合内容。除非在对文档进行验证的时候,同级元素或PCDATA的出现次序一般来说并不重要。
以数据为中心的文档中的这类数据可以来自数据库(此时要输入给XML)或在数据库之外(此时要将其存入数据库)。前者的一个例子就是关系数据库现存的大量数据;而从测量系统采集并转化为XML的科研数据就是后者的例子。
例如,下面的销售订单就是以数据为中心的: <SalesOrder SONumber="12345">
<Customer CustNumber="543">
<CustName>ABC Industries</CustName>
<Street>123 Main St.</Street>
<City>Chicago</City>
<State>IL</State>
<PostCode>60609</PostCode>
</Customer>
<OrderDate>981215</OrderDate>
<Item ItemNumber="1">
<Part PartNumber="123">
<Description>
<p><b>Turkey wrench:</b><br />
Stainless steel, one-piece construction,
lifetime guarantee.</p>
</Description>
<Price>9.95</Price>
</Part>
<Quantity>10</Quantity>
</Item>
<Item ItemNumber="2">
<Part PartNumber="456">
<Description>
<p><b>Stuffing separator:<b><br />
Aluminum, one-year guarantee.</p>
</Description>
<Price>13.27</Price>
</Part>
<Quantity>5</Quantity>
</Item>
</SalesOrder>
除了像销售订单这种显而易见的以数据为中心的文档之外,许多以文本为主的(prose-rich)文档也可以是以数据为中心的。例如,Amazon.com用来显示书籍信息的一个页面。尽管页面上大部分内容都是文本,这些文本的结构是非常规则的,许多都和其它书籍的描述相同,每个页面特有的文本并不很多。这样,就可以从数据库中取出书籍的相关资料,转换为简单的、以数据为中心的XML文档,再用XSL样式表生成页面。一般来说,那些用数据库中的数据填充模板,动态生成HTML文件的网站都可以转而使用一系列以数据为中心的XML文档和XSL样式表。
例如,下面是个描述航班信息的文档: <FlightInfo>
<Airline>ABC Airways</Airline> provides <Count>three</Count>
non-stop flights daily from <Origin>Dallas</Origin> to
<Destination>Fort Worth</Destination>. Departure times are
<Departure>09:15</Departure>, <Departure>11:15</Departure>,
and <Departure>13:15</Departure>. Arrival times are minutes later.
</FlightInfo>
从下面的XML文件和一个简单的样式表中创建这个文档: <Flights>
<Airline>ABC Airways</Airline>
<Origin>Dallas</Origin>
<Destination>Fort Worth</Destination>
<Flight>
<Departure>09:15</Departure>
<Arrival>09:16</Arrival>
</Flight>
<Flight>
<Departure>11:15</Departure>
<Arrival>11:16</Arrival>
</Flight>
<Flight>
<Departure>13:15</Departure>
<Arrival>13:16</Arrival>
</Flight>
</Flights>
4.2 以文档为中心的文档 (Document-Centric Documents)
以文档为中心的文档通常是供人消费的。例如书籍、email、广告以及几乎所有人工写成的XHTML文件。其特性为结构不太或根本不规则、数据粒度大(larger grained data)(最小的独立数据单位可能存在于包含混合内容的元素甚至整个文档本身),混合内容多。同级元素或PCDATA出现的次序一般来说总是非常重要的。
以文档为中心的文档通常是以XML手工写成,或从其他格式(如RTF, PDF, SGML)转换到XML,与以数据为中心的文档不同,它们通常不来源于数据库。(由插入到模板中的数据得到的文档是以数据为中心的;更多信息请看4.1节末尾部分)。将各种格式转换为XML的软件信息,请参阅XML软件相关链接。
例如,下面这个产品说明是以文档为中心的: <Product>
<Intro>
The <ProductName>Turkey Wrench</ProductName> from <Developer>Full
Fabrication Labs, Inc.</Developer> is <Summary>like a monkey wrench,
but not as big.</Summary>
</Intro>
<Description>
<Para>The turkey wrench, which comes in <i>both right- and left-
handed versions (skyhook optional)</i>, is made of the <b>finest
stainless steel</b>. The Readi-grip rubberized handle quickly adapts
to your hands, even in the greasiest situations. Adjustment is
possible through a variety of custom dials.</Para>
<Para>You can:</Para>
<List>
<Item><Link URL="Order.html">Order your own turkey wrench</Link></Item>
<Item><Link URL="Wrenches.htm">Read more about wrenches</Link></Item>
<Item><Link URL="Catalog.zip">Download the catalog</Link></Item>
</List>
<Para>The turkey wrench costs <b>just $19.99</b> and, if you
order now, comes with a <b>hand-crafted shrimp hammer</b> as a
bonus gift.</Para>
</Description>
</Product>
4.3 数据、文档和数据库(Data, Documents, and Databases)
实际上,以数据为中心和以文档为中心的文档之间的差别不一定很明显。例如,另一种以数据为中心的文档比如发票,可能含有大粒度的、非结构化的数据比如零件说明;另一种以文档文中心的文件如用户手册,可能包含细粒度的结构规则的数据(通常为元数据)比如作者和修订日期。其它例子包括法律和医学文书,虽然以散文的形式写成但是却包含离散的数据块例如日期、名称和操作程序,出于法定原因通常要以完整的文件形式存储。
除此之外,弄清文件的这两种特点有助于选择数据库的类型。一般来说,将数据存储于传统的数据库,例如关系型,面向对象型或层次型数据库。这可由第三方的中间件完成或由数据库本身提供内在支持。对于后者,该数据库被称作支持XML的(XML-enabled)。文档可被存储在原生(native)XML数据库(专为存储XML而设计的数据库)或内容管理系统(建在原生XML数据库之上专门用来管理文档的程序)。
这些原则并不是绝对的。如果对XML特有的功能不很看重,数据,特别是半结构化的数据可以存储在原生XML数据库,文档也可以存储到传统数据库。何况传统数据库与原生XML数据库之间的界限越来越模糊,传统数据库增加了原生XML的能力,而原生XML数据库增加了对文档存储在外部(通常为关系型)数据库的支持。
本文剩下的部分就有关数据(第5节)和文档(第6节)的存储和读取的策略与问题展开讨论。关于最新的XML数据库产品,请见 XML Database Products。
5.0 数据的存取(Storing and Retrieving Data)为了在XML文件和数据库之间交换数据,有必要将XML文件的schema(DTD,XML Schema, RELAX NG等)映射到数据库的schema。用于数据转换的软件就建在这种映射之上。该软件可以使用XML Query语言(如XPath,XQuery,或其他专用语言)或简单地按照映射(SELECT * FROM Table的XML对等式)转换数据。
对于后者,文档的结构必须完全符合映射所要求的结构。由于通常不易做到这点,使用这种策略的产品一般要和XSLT一起使用。在数据转换到数据库之前,先将文件按照映射所要求的结构进行转换,然后转存数据。相应地,数据从数据库中取出以后,结果文件要被转换成应用程序所需的结构。
5.1 映射[XML]文件Schema到数据库Schema (Mapping Document Schemas to Database Schemas)
文件schema到数据库schema的映射是在元素类型、属性和文本上进行的。这时几乎总是忽略物理结构(例如实体、CDATA部分及编码信息)及某些逻辑结构(如处理指令、注释以及元素和PCDATA在父元素内出现的顺序)。这样比完全照搬更为合理,因为数据库和应用程序只需关心XML文件中的数据。例如,在上述的销售订单中,客户代号是在CDATA部分,还是外部实体中,或直接就是PCDATA并不重要,同样,客户代号出现在订货日期之前或之后也无关紧要。
这种方法的一个后果是能否保证文件有“往返车票” -- 将文件中的数据存入数据库后,又从数据库中的数据建立文件,而这个文件往往和原来的文件不同(哪怕从最一般的意义上讲)。在选择软件是要考虑到是不是允许这种情形发生。
将一个XML文件的schema映射到数据库的schema有两种方法:基于表格的映射和对象-关系映射。
5.1.1 基于表格的映射 (Table-Based Mapping)许多转换XML到数据库的中间软件都采用基于表格的映射。它把XML文件看作一个(或一组)表格,也就是说,XML文件的结构必须是下面这种样子,如果只是单一表格的话,就不再需要<database>元素和其他<table>元素: <database> <table> <row> <column1>...</column1> <column2>...</column2> ... </row> <row> ... </row> ... </table> <table> ... </table> ... </database>根据所用软件的不同,可以指定将各字段数据以子元素或属性存储,也可以指定这些元素或属性的名字。此外,采用基于表格映射方式的软件还可能允许在文件开始的地方包含表格或各字段的元数据,或者将其作为各表格或元素的属性。注意这里所说的“表格”是泛指的表格。当将数据从数据库中转到XML文件时,“表格”可以是任何结果集,反之,“表格”可以是普通的表格或可更新的视图。 基于表格的映射对存取关系型数据比较适用,比如在两个关系型数据库之间转换数据。其明显不足就是不适于与上述格式不符的XML文件。 5.1.2 对象-关系映射 (Object-Relational Mapping)
所有支持XML的关系型数据库和某些中间件都可以使用对象-关系的映射方式。它将XML文件中的数据视为特定的对象树的模型。在这个模型中,元素及其类型、元素内容或混合内容(复合元素类型)通常被视为类。只具有PCDATA内容的元素(简单元素类型)、属性以及PCDATA都被当作简单属性。然后通过传统的对象-关系映射技术或SQL 3的对象视图将该模型映射到关系型数据库。也就是说,类被映射到表格,简单属性被映射到字段,而值为对象属性被映射为成对的主键/外键(primary key/foreign key)。
(所谓“对象-关系映射”实际上名不副实。因为对象树可以被直接映射到面向对象型和层次型数据库,然而,但是由于大多数使用这种映射方式的主流产品使用的其实是关系型数据库,所以“对象-关系映射”也就广为人知。)
我们在理解这种映射所用的对象模型的时候要知道,这个对象模型不是文件对象模型(DOM)。所有XML文件的DOM都是一样的,而上述描述文件数据的模型对于每个DTD所定义的XML文件都不一样,例如,上述销售订单的模型是一个由四个类所组成的对象树--SalesOrder, Customer, Item, 和Part, 如下图所示: SalesOrder
/ | \
Customer Item Item
| |
Part Part
在由同一个文件产生的DOM中,对象树的组成是元素、属性和文本:
元素 --- 属性
(SalesOrder) (SONumber)
____/ / \ \_____
/ / \ \
元素 文本 元素 元素
(Customer) (OrderDate) (Item) (Item)
| | |
etc. etc. etc.
模型中的对象是否被实例化要取决于所用的软件。有些软件允许依据模型产生类,然后可以在程序中使用由这些类所产生的对象。在这些产品中,数据是在XML文件 - 对象 - 数据库之间传递的。其他产品是直接在XML文件和数据库之间进行数据转换的,对象只是作为这种过程的可视化帮助工具。生成这些中间对象是否有用完全取决于你的应用程序。
(根据Sun的 Java Architecture for XML Binding,XML文件与对象的绑定通常被称为XML数据绑定(XML data binding), 有些产品支持XML数据绑定,其中许多还可以在对象和数据库之间进行数据交换,更多的信息,请看 XML数据绑定相关资源 XML Data Binding Resources.)
各种产品支持对象-关系映射的具体实现方法有所不同。例如:
所有产品都支持从复合元素类型到类,以及从简单元素类型和属性(attributes)到[类的]属性(properties)的映射。
几乎所有产品都允许你指定根元素不被映射到对象模型或数据库。如果你想在同一个XML文档中存储多个顶级对象时,这个包装元素(wrapper element)就显得有用了。例如,如果你想在同一个XML文件中存储多个销售订单,就必须把它们包装在一个根元素内。
当使用基于表格的映射的XML文件有多个表格组成时,这个包装元素就相当于<database>元素,这是因为根据目前的标准,XML文件只能有一个根元素。少数产品允许你在较低的层次上指定包装元素。
大多数产品允许你说明将[对象的]属性(properties)映射到XML文件中的属性(attribute)还是子元素。某些产品还允许你混合使用属性和子元素,其他的只允许你使用两者之一。
大多数产品允许XML文件和数据库的名字可以不同。少数产品要求必须使用相同的名字。
大多数产品允许你说明子元素在父元素中的出现次序,尽管如此,要建立多个内容模型仍是不可能的。幸好对于大多数以数据为中心的文档而言,所提供的内容模型已经足够。(当文件需要验证时,子元素的次序相当重要。)
某些产品允许你将复合元素类型映射到简单属性(properties)。当某个元素包含混合内容(例如销售订单中的<Description>元素)时,这点相当有用。尽管<Description>元素像XHTML一样包含子元素和文本,但最好还是将这个description视为单个属性,而不是把它分成许多碎块。
支持混合内容中的PCDATA映射的产品不多。
关于对象-关系型映射的详细描述,请看第三部分“将DTD映射到数据库”。
5.2 查询语言(Query Languages)
许多产品都是按照它们所建的模型直接进行数据交换。由于XML文件的结构和数据库的结构一般不同,这些产品一般都使用了或包括了XSLT样式表。这就允许用户在数据被交换到数据库之前(或相反)根据模型规定的格式对文件进行转换。由于XSLT处理的代价较高,某些产品只提供有限几种这样的转换。
这个问题的长久解决方案就是设计一种可以返回XML[文件]的查询语言。目前来看(2002年2月),大多数这种语言都是在模板中嵌入SELECT语句。到XQuery最后定稿时这个局面有望得到改变,正如主流的数据库产品提供商已经做的那样。不幸的是,几乎所有的XML查询语言(包括XQuery1.0)都只能读取数据,所以当前最需要的是能够插入、更新、删除数据的手段。(从长远来看,XQuery将会增加这种功能。)
5.2.1 基于模板的查询 (Template-Based Query)
大多数从数据库读取XML的查询语言是基于模板的,这些语言并没有预先定义XML文件和数据库之间的映射,相反,是将SELECT语句嵌入到模板中,由数据交换软件对结果进行处理。例如,下面的模板(并不是真正产品中的)使用包含了SELECT语句和$column-name值的<SelectStmt>元素来决定将结果放在何处。 <?xml version="1.0"?>
<FlightInfo>
<Introduction>The following flights have available seats:</Introduction>
<SelectStmt>SELECT Airline, FltNumber, Depart, Arrive FROM Flights</SelectStmt>
<Flight>
<Airline>$Airline</Airline>
<FltNumber>$FltNumber</FltNumber>
<Depart>$Depart</Depart>
<Arrive>$Arrive</Arrive>
</Flight>
<Conclusion>We hope one of these meets your needs</Conclusion>
</FlightInfo>
这个模板处理之后的结果可能是:
<?xml version="1.0"?>
<FlightInfo>
<Introduction>The following flights have available seats:</Introduction>
<Flights>
<Flight>
<Airline>ACME</Airline>
<FltNumber>123</FltNumber>
<Depart>Dec 12, 1998 13:43</Depart>
<Arrive>Dec 13, 1998 01:21</Arrive>
</Flight>
...
</Flights>
<Conclusion>We hope one of these meets your needs.</Conclusion>
</FlightInfo>
基于模板的查询语言可以做到非常灵活。尽管各个产品的功能不尽相同,但有一些共同特性:
可以将返回结果放在输出文件中的任何地方,包括作为后续SELECT语句的参数。
可由程序构建 for 循环和 if 语句。
可以定义变量和函数。
可通过HTTP参数实现SELECT语句的参数化(parameterization)。
从关系数据库中将数据转换到XML文件时,几乎一定要用到基于模板的查询语言。虽然有些产品也将基于模板的查询语言用于XML文件到关系数据库的数据转换,这时所用的并不是完整的模板语言。相反,他们使用的是上面所述的基于表格的映射。
5.2.2 基于SQL的查询语言 (SQL-Based Query Languages)
基于SQL的查询语言使用的是经过修改的SELECT语句,[查询]结果被转换为XML。通过简单地使用嵌套的SELECT语句,就可直接转换成符合对象-关系映射的嵌套的XML。或者使用SQL 3的对象视图也可直接转换成XML。最后还可使用 OUTER UNION语句和特殊标记来决定怎样将结果转换成XML。
5.2.3 XML Query Languages
基于模板和基于SQL的查询语言只能用于关系数据库,与此不同,XML查询语言可用于任何XML文档。为了把它用于关系数据库,必须把数据库中的数据看作XML的模型,这样才能对虚拟的XML文件进行查询。
对于XQuery, 基于表格的映射或对象-关系型映射都可以使用。当使用基于表格的映射时,各个表格被视为单独的文件,像SQL中的一样, 这些表格的结合(joints)则在查询[语句]本身中指明。如果使用的是对象-关系型映射,各个表格的层次被当作单个文件,而[表格的]结合在映射中说明。对于大多数关系数据库而言,似乎基于表格的映射更为常用,这是因为它的实现似乎更简单些,SQL的用户对此也更为熟悉。
如果使用XPath在多个表格中进行查询,就必须使用对象-关系映射,这是因为XPath不支持多个文档。因此,如果使用基于表格的映射,可能每次只能对一个表格进行查询。