级别: 中级 Mirella Moura Moro (mirella@cs.ucr.edu), 助理研究员, Universidade Federal do Rio Grande do Sul Susan Malaika (malaika@us.ibm.com), 高级技术职员, IBM Lipyeow Lim (liplim@us.ibm.com), 研究人员, IBM
2007 年 9 月 07 日 不断演化的 Web 环境对 Web 应用程序或服务底层的数据库提出了如何适应新功能、新数据类型的挑战。对于 XML 数据库,每六个月可能就要发布新的模式版本。本文讨论了适用于 XML 模式演化过程的变化的分类。然后分析了这些变化对模式验证过程(包括向前和向后兼容)以及查询求值的影响。从案例研究出发,本文提出了 XML 模式演化以及编写跨模式版本查询的基本原则。
随着 XML 越来越多地作为信息交换标准,持久、验证和查询 XML 文档的功能也越来越重要。此外,随着 Web 服务和 mash-up 应用程序的泛滥,Web 应用开发人员也更多地需要转换 XML 消息,不论这些消息直接来自 Web 服务还是间接来自持久这些消息的数据库。
多数商业数据库管理系统已经以某种形式支持 XML 持久性。比如,IBM DB2® pureXML™(请参阅 参考资料)天生就支持在 XML 类型列中存储 XML 文档、用 XML 模式验证 XML 文档、使用 XQuery 和 SQL/XML 查询语言查询 XML 文档。可以在同一列中存储和查询模式不同但结构良好的 XML 文档。
此外,不断变化的 Web 环境要求数据库适应新的功能(比如组织业务的扩展)和新数据类型(比如 RSS 提要消息)。可能每六个月就出现新的模式版本 — 有时候甚至只有两周。信息技术架构师、应用程序开发人员和数据库管理员经常发现,如果应用程序操作的 XML 文档列使用不同版本的模式,管理起来就非常乱。另外,数据库之上的应用程序及其用户仍然需要和其交互,不论模式如何变化。
由于上述这些原因,模式演化作为一项重要课题需要在关系、面向对象和 XML 数据库环境中加以研究。具体来说,对于 XML 数据库,模式演化是 XML 的迫切要求。虽然以前的大部分工作考虑的是模式演化的技术方面(即如何有效存储不同的模式,在变化中保持数据一致性),本文的目标是讨论如何在不断演化的模式中保持查询的完整性。只要按照这里提供的建议操作,数据库就能跟上 Web 应用程序发展的需要,Web 应用程序仍然能够保持与数据库的交互(通过查询)。这方面研究具有重要的意义:
- 我们考虑了在 XML 模式演化过程中最常见的变化类型并提出了一种分类方法。
- 按照这种分类,说明每种变化对模式验证的影响。同时考虑到了向前兼容(即旧模式的文档和新模式兼容)和向后兼容(即新模式的文档和旧模式兼容)。
- 我们提出并讨论了模式演化对查询公式的影响。换句话说,对旧模式文档执行的查询不一定能用于新模式文档(反之亦然)。
- 我们提出了管理 XML 模式演化的基本原则,说明如何控制模式变化以及如何编写跨越不同模式版本的查询。
下面介绍 XML 和 XQuery 的一些基本概念。“XML 模式变化分类” 一节提出了模式演化过程中可能出现的变化类型。“XML 模式演化对查询的影响” 讨论了这种影响,并通过保险业的例子说明了模式变化、查询和查询结果之间的交互。为了让查询在模式演化的时候仍然返回预期的结果,“管理 XML 模式演化的基本原则” 就此提出了管理模式演化的基本原则。
背景
XML(可扩展标记语言)是源于 SGML 的一种标记语言,其规范由 W3C 管理。使用 XML 有利于开发适用于多种环境的应用程序。XML 一直在 Web 服务应用程序中使用,RSS 提要是一个典型的例子。Web 服务也从消息传递环境中的结构化数据获益。另外,XML 有助于建立文件格式的公开标准,促进不同平台、不同应用程序间的数据交换。此外,通用 XML 数据结构可以改进电子商务参与方之间的集成,更有效地交换订单、库存信息和发货细节。XML 数据封装也提高了访问的机密性和可靠性,无论通过 Web 还是桌面应用程序访问。
最后,可以为结构化 XML 数据实现高效的文档搜索方法。和二进制数据不同,XML 是高度结构化的,很多解析器和工具针对 XML 数据搜索和查询进行了优化。清单 1 是关于图书馆的一个简单 XML 文档。
清单 1. 简单的 XML 文档
<?xml version="1.0" encoding="UTF-8"?>
<library>
<book edition="5">
<title>Fundamentals of Database Systems</title>
<author>Ramez Elmasri</author>
<author>Shamkant B. Navathe</author>
<year>2006</year>
<publisher>Benjamin/Cummings</publisher>
<category>Computer Science
<subcategory>Databases</subcategory>
</category>
</book>
<book edition="3" format="hardcover">
<title>Mists of Avalon</title>
<info>Marion Zimmer Bradley, published by Del Rey</info>
<category>Fiction</category>
</book>
</library>
|
从这个例子可以看出,与关系数据不同,XML 数据通常是无模式和自描述的,但是展现出一种固有结构。这种结构主要通过元素(<library> 和 <book>)和属性(edition 和 format)来定义。每个元素都有很多属性(以及相应的值),元素中嵌套元素和文本内容。
通常,只有结构良好 和有效 的 XML 文档才能被应用程序处理。符合 XML 语法规则的文档是结构良好的。比如,XML 文档必须有且只有一个根元素。符合 XML 模式的文档是有效的。模式定义了文档的组织规则和内容。比如,图书馆中的每个 <book> 必须有一个 <title> 元素,而且不能嵌套在其他 <book> 中。定义 XML 模式的多种语言之中,最常用的一种被简称为 XML Schema。
如果信息用 XML 文档给出,可以用 XML 查询语言如 XQuery 检索数据。XQuery 使用 XPath 表达式访问文档的特定部分。清单 2 中给出了一个简单的 XPath 表达式,检索 2006 年出版的图书。
清单 2. 简单的 XPath 表达式
/library/book[year="2006"]//subcategory
|
XPath 表达式并入到通过 FLWOR(For、Let、Where、Order by、Return)表达式指定的 XQuery 语句中。比如,清单 3 中的 XQuery 表达式按标题顺序返回 2006 年 Benjamin/Cummings 出版的图书。
清单 3. XQuery
for $b in doc("mylibrary.xml")//book
where $b/publisher="Benjamin/Cummings"
order by $b/year
return $b/title
|
XML 模式变化的分类
在模式演化过程中,模式的任何成分都可能随着版本的不同而变化。这一节介绍和验证有关的不同的模式变动类型。首先可以分为基本变化和复杂变化。然后说明它们对验证文档的影响。
基本变化
FpML Architecture Working Group 围绕 FpML 提出把模式的变化分为五种类型,FpML 是定义信息共享、处理、交换、派生及其他结构化产品的商业产品标记语言(关于这种分类的更多信息请参阅 参考资料)。表 1 列出了模式定义最常见的变化类型。同时说明对于每种变化,旧模式的文档实例根据新模式是否有效(向前兼容),新模式的文档实例根据旧模式是否有效(向后兼容)。
这些变化反映了不同行业的实际情况。但必须认识到,由于 XML 模式语言(比如 DTD 和 XML Schema)是扩展的,也可能出现其他类型的变化。此外,虽然一些复杂变化可归为基本变化的组合(比如删除后的精化),但为了 下一节 中更好的理解仍然单独列出。请注意,大部分复杂变化,旧模式的文档实例对于新模式通常都不再有效,或者需要应用程序的某些支持。通过 下一节 中的例子可以很清楚地看到这点。此外,基本变化中,只有精化和删除可能引起兼容性问题,通过示例分析将很清楚看到这点。
表 1. 基本的模式变化及其对验证的影响
| 变化的名称 | 定义 | 向前兼容 | 向后兼容 |
|---|
| 精化 | 为模式增加可选或者必须的元素。 | 只有插入的元素是可选的(或者在 choice 元素中),根据旧模式创建的文档才能兼容新模式。 | 如果没有实例化新的元素,根据新模式创建的文档才会与旧模式兼容。 |
|---|
| 删除 | 从模式中删除元素 | 只有删除的元素是可选的并且没有出现在实例中,才能兼容。 | 和向前兼容相同。 |
|---|
| 扩展 | 向模式增加对当前结构没有重大影响的新结构。比如增加复杂类型。 | 兼容。 | 只有根据新模式创建的文档没有用到新结构的时候才能保持兼容。 |
|---|
| 重释 | 改变元素的语义但不改变其结构(即语法定义)。 | 语法上兼容 | 和向前兼容相同。 |
|---|
| 重定义 | 升级模式定义但不改变文档实例的格式。比如抽取公共结构。 | 如果重定义保持名称和类型不变的话则兼容。 | 和向前兼容相同。 |
|---|
复杂变化
表 1 中的变化很常见,但是没有涵盖所有可能的情况。本文扩展了这种分类,增加了几种更复杂的变化类型,如 表 2 所示。
表 2. 复杂的模式变化及其对验证的影响
| 变化的名称 | 定义 | 向前兼容 | 向后兼容 |
|---|
| 元素组合 | 将相关元素划分到一个新元素下。比如把 <lastName> 和 <FirstName> 放到新元素 <personName> 中。 | 可能不兼容。 | 可能不兼容。 |
|---|
| 元素分解 | 和元素组合相反:将组合的子元素分解成单独的元素。 | 可能不兼容。 | 可能不兼容。 |
|---|
| 重命名 | 改变元素或属性的名称。 | 不兼容,除非上层应用程序进行补偿 — 比如定义同义词规则。 | 和向前兼容相同。 |
|---|
| 可选化 | 将元素的参与语义从可选变成必须或者相反。 | 从可选到必须:如果元素一直存在则兼容。从必须到可选:兼容。 | 从可选到必须:兼容。从必须到可选:只有当元素一直有的时候才兼容。 |
|---|
| 重新编号 | 改变元素的基数 — 即多倍性约定。比如从一个变成多个。 | 从一到多:兼容。从多到一:只有每个元素仅存在一个实例的情况下才兼容。 | 从一到多:只有每个元素都只存在一个实例的情况下才兼容。从多到一:兼容。 |
|---|
| 改变类型 | 改变元素的数据类型。包括扩展元素和使用刻面限制元素。 | 除非上层应用程序规定转换规则,否则不兼容。 | 和向前兼容相同。 |
|---|
| 默认值 | 改变属性或元素的默认值。 | 如果不改变值的类型,兼容。 | 和向前兼容相同。 |
|---|
| 名称空间 | 改变名称空间。 | 不兼容。 | 不兼容。 |
|---|
| 改变顺序 | 改变复杂类型中元素的顺序。 | Sequence 到 all:兼容。all 到 sequence:一般不兼容。sequence 内改变顺序:不兼容。 | sequence 到 all:一般不兼容。all 到 sequence:兼容。sequence 内改变顺序:不兼容。 |
|---|
XML 模式演化对查询的影响
模式变化除了影响验证之外,各种变化还影响查询公式:针对旧模式文档的查询不一定适用于新模式文档(反之亦然)。这一节通过一系列基于 ACORD(Association for Cooperative Operations Research and Development)模式(请参阅 参考资料)的例子,讨论模式演化对查询及其结果的影响。ACORD 协会为保险、再保险及相关金融服务业制定标准。实际上,ACORD 平均每月发布一次新模式,示例中使用的变化仅仅是为了说明问题,不代表实际模式的变化。查询的是金融交易中参与者的个人信息而不是 ACORD 标准的金融信息。
一般查询
我们首先给出两个一般的查询,不访问修改的模式元素。每个查询都有自己的规范(类似于 XQuery 表达式)和基于 清单 4 所示实例文档的结果(包括旧模式和新模式的文档实例)。为了清晰,清单中包括实例的图形化表示而不是模式规范。
清单 5、6 和 7 表明如果查询不访问修改过的元素,结果差不多。其中,清单 5 检索每个实例的全部交易,对查询没有限制;清单 6 检索交易的特定元素(姓氏),清单 7 和清单 6 相同,但是按交易 ID 对结果分组。这些例子很简单,说明如果查询中不涉及模式的演化部分就没有什么问题。但是,情况并非总是如此,如下一组例子所示。
清单 4. 模式修改的文档实例:精化 <SSN> 元素,删除 <BirthDate> 元素
旧模式的文档实例
<TXLife>
<TXLifeRequest id="TXLifeRequest1001">
<TransRefGUID>2006-0712-1001</TransRefGUID>
<TransType tc="103">Schema Evolution </TransType>
<OLifE>
<Party id="ID1101">
<Person>
<FirstName>Alan</FirstName>
<LastName>Bird</LastName>
<Gender>MALE</Gender>
</Person>
</Party>
<Party id="ID1102">
<Person>
<FirstName>Anthony</FirstName>
<LastName>Bell</LastName>
<Gender>MALE</Gender>
<BirthDate>1975-11-14</BirthDate>
</Person>
</Party>
</OLifE>
</TXLifeRequest>
</TXLife>
|
新模式的文档实例
<TXLife>
<TXLifeRequest id="TXLifeRequest1002">
<TransRefGUID>2006-0712-1001</TransRefGUID>
<TransType tc="103">Schema Evolution </TransType>
<OLifE>
<Party id="ID1103">
<Person>
<FirstName>Carl</FirstName>
<LastName>Devon</LastName>
<Gender>MALE</Gender>
<SSN>606-23-0987</SSN>
</Person>
</Party>
<Party id="ID1104">
<Person>
<FirstName>Cinthia</FirstName>
<LastName>Din</LastName>
<Gender>FEMALE</Gender>
</Person>
</Party>
</OLifE>
</TXLifeRequest>
</TXLife>
|
|
清单 5. 检索 Schema Evolution 示例中全部交易
XQuery
for $trans in //TXLifeRequest return $trans
|
结果
结果是包含旧文档和新文档中都有的交易的 return 元素。
|
清单 6. 检索所有 <LastName> 元素的值
XQuery
for $trans in //TXLifeRequest//LastName
return <result>{$trans}</result>
|
结果
<result>
<LastName>Bird</LastName><LastName>Bel</LastName>
<LastName>Devon</LastName><LastName>Din</LastName>
</result>
|
|
清单 7. 检索所有 <LastName> 元素的值,按交易分组
XQuery
for $trans in //TXLifeRequest
for $tid in $trans/@id let $t:=$trans//LastName
return
<TX>
{$tid}
<Names>
{$t}
</Names>
</TX>
|
结果
<result>
<LastName>Bird</LastName><LastName>Bel</LastName>
<LastName>Devon</LastName><LastName>Din</LastName>
</result>
|
|
基本变化
在前述五种基本变化类型中,我们主要讨论精化 和删除,因为它们影响查询公式和结果。其他变化对查询计算没有显著的影响(扩展 不会产生问题,除非新元素使用新的结构定义 — 这样就相当于进行了精化;重释 和重定义 对元素的结构没有影响)。因此只有精化和删除和下一节有关。这一节中讨论的所有示例都是后面所述 基本原则 的基础。
精化
清单 4 中的第一种基本变化是 ACORD 模式的扩展,增加了一个可选元素表示参与者的社会安全号码(SSN)。清单 8 返回参与交易的所有人的姓氏,如果有 SSN 的话同时返回。因此,检索了四个参与者(包括旧文档和新文档)和一个 SSN。虽然查询访问新元素,它的访问也仅限于 return 子句 — 就是说是非限定性的。换句话说,清单 10 的 where 语句中有一个 exist 子句,要求具有 SSN 的那些人的名字。因此,查询处理仅限于新模式文档实例,因为旧模式的所有实例计算 where 语句的结果都是 false。清单 10 还说明如何编写查询才能保持跨模式的能力。
清单 8. 检索姓氏和 SSN,按参与者和交易分组
XQuery
for $trans in //TXLifeRequest
for $tid in $trans/@id
return
<TX>
{ $tid }
{ for $P in $trans//Party
return
<Party>
{$P//LastName}
{$P//SSN}
</Party> }
</TX>
|
结果
<TX id="TXLifeRequest1001">
<Party><LastName>Bird</LastName></Party>
<Party><LastName>Bell</LastName></Party>
</TX>
<TX id="TXLifeRequest1002">
<Party>
<LastName>Devon</LastName>
<SSN>606-23-0987</SSN>
</Party>
<Party><LastName>Din</LastName>
</Party>
</TX>
|
|
清单 9. 模式变化的文档实例:元素组合
旧模式的文档实例
<TXLife>
<TXLifeRequest id="TXLifeRequest1001">
<TransRefGUID>2006-0712-1001</TransRefGUID>
<TransType tc="103">Schema Evolution</TransType>
<OLifE>
<Party id="ID1101">
<Person>
<FirstName>Alan</FirstName>
<LastName>Bird</LastName>
<Gender>MALE</Gender>
</Person>
<Address>
<Line1>998 Mamaroneck Ave</Line1>
<City>White Plains</City>
<AddressStateTC tc="60">NY</AddressStateTC>
<Zip>10605</Zip>
</Address>
</Party>
</OLifE>
</TXLifeRequest>
</TXLife>
|
新模式的文档实例
<TXLife>
<TXLifeRequest id="TXLifeRequest1002">
<TransRefGUID>2006-0712-1001</TransRefGUID>
<TransType tc="103">Schema Evolution</TransType>
<OLifE>
<Party id="ID1103">
<Person>
<FirstName>Carl</FirstName>
<LastName>Devon</LastName>
<Gender>MALE</Gender>
</Person>
<Address>20 Fifth Ave, New York, NY 10011</Address>
</Party>
</OLifE>
</TXLifeRequest>
</TXLife>
|
|
删除
清单 4 中的第二项变化是从 ACORD 模式中删除了 <BirthDate> 元素。清单 11 对第一个文档实例返回出生日期列表,对第二个实例却返回空白列表。如果只能检索包含出生日期元素的交易,必须在 where 语句中使用 exists 函数,如 清单 10 所示。这里仅计算旧模式文档。
清单 10. 检索提供 SSN 的人员的姓氏,按角色和交易分组
XQuery
for $trans in //TXLifeRequest
for $tid in $trans/@id
where fn:exists($trans//SSN)
return <TX>{$tid}
{ for $P in $trans//Party
where fn:exists($P//SSN)
return
<Party> {$P//LastName}</Party> }
</TX>
|
结果
<TX id="TXLifeRequest1002">
<Party>
<LastName>Din</LastName>
</Party>
</TX>
|
|
清单 11. 检索交易 ID 及出生日期列表
XQuery
for $trans in //TXLifeRequest
for $tid in $trans/@id
return <TX>{$tid}
{ for $P in $trans//Party//BirthDate
return $P}
</TX>
|
结果
<TX id="TXLifeRequest1001">
<BirthDate>1975-11-14</BirthDate>
</TX>
<TX id="TXLifeRequest1002"/>
|
|
清单 12. 检索 TXLifeRequest ID 和地址列表
XQuery
for $trans in //TXLifeRequest
for $tid in $trans/@id return <TX>{$tid}
{ for $P in $trans//Address return $P}</TX>
|
结果
<TX id="TXLifeRequest1001">
<Address>
<Line1>998 Mamaroneck Ave</Line1>
<City>White Plains</City>
<AddressStateTC tc="60">NY</AddressStateTC>
<Zip>10605</Zip>
</Address>
</TX>
<TX id="TXLifeRequest1002">
<Address>20 Fifth Ave, New York,
NY 10011</Address>
</TX>
|
|
复杂变化
这一节讨论复杂变化对查询公式的影响。和基本变化一样,每个查询都有相当于 XQuery 语句的规范和结果。
元素组合
清单 9 描述了这种变化,<Address> 子元素由一个简单元素(没有子结构)组成。清单 12 给出了一个检索地址的有趣的示例,因为它能从两个实例中返回地址信息,但结果用不同的结构表示。
这类变化有两方面的问题:
- 其一,新的组成元素可能和原来的结构元素不同名。这类变化的结果和重命名类似。
- 其二,查询可能引用旧模式特定的子结构。比如,清单 14 请求地址中的邮政编码。因此,结果仅返回第一个实例中的地址,因为第二个实例中不存在
<Zip> 元素。后一种情况对查询的影响极其重要,因为即使没有数据损失,数据的限定也没有了。
清单 13. 模式变化的文档实例:重命名
旧模式的文档实例
<TXLife>
<TXLifeRequest id="TXLifeRequest1001">
<TransRefGUID>2006-0712-1001</TransRefGUID>
<TransType tc="103">Schema Evolution</TransType>
<OLifE>
<Party id="ID1101">
<Person>
<FirstName>Alan</FirstName>
<LastName>Bird</LastName>
<Gender>MALE</Gender>
</Person>
</Party>
</OLifE>
</TXLifeRequest>
</TXLife>
|
新模式的文档实例
<TXLife>
<TXLifeRequest id="TXLifeRequest1002">
<TransRefGUID>2006-0712-1001</TransRefGUID>
<TransType tc="103">Schema Evolution</TransType>
<OLifE>
<Party id="ID1103">
<Person>
<fName>Carl</fName>
<lName>Devon</lName>
<Gender>MALE</Gender>
</Person>
</Party>
</OLifE>
</TXLifeRequest>
</TXLife>
|
|
清单 14. 检索 TXLifeRequest ID 和地址的邮政编码
XQuery
for $trans in //TXLifeRequest
for $tid in $trans/@id
return <TX>{$tid}
{ for $P in $trans//Address//Zip return $P } </TX>
|
结果
<TX id="TXLifeRequest1001">
<Zip>10605</Zip>
</TX>
<TX id="TXLifeRequest1002"/>
|
|
元素分解
这里的例子和 清单 9 的情况正相反:我们把新旧文档颠倒一下。如果分解后的结构名称保持不变,那么查询的惟一区别在于新模式的查询结果是结构化的。组合中的同样问题对分解来说恰恰相反。
重命名
清单 13 中的例子把元素 <FirstName> 和 <LastName> 重命名为 <fName> 和 <lName>。对查询的影响取决于是否直接引用这些元素名。比如 清单 15 按交易找人,因此两个实例都有结果。如果查询规定返回 //Person/LastName,就只有第一个实例有结果了。
解决这个问题的一种办法是为数据库上层的应用程序建立同义词表。另一种办法是在查询中指定所有的名称。这种解决方案不够优雅,而且需要了解模式。清单 16 给出了一个例子。
可选性
这种变化在某些方面与精化和删除有关。将元素从可选变为必须涉及到旧文档中没有实例化的可选元素的精化。比如,将 <SSN> 元素从可选变为必须,对 清单 8 和 9 的影响相同,假设旧实例中没有给出该元素的值。类似的,将元素从必须变为可选将影响引用原来必须元素的查询的结果。这种情况下可能出现结果为空。将元素 <birthDate> 从必须改为可选,其后果如 清单 11 所示,假设新实例中没有给出它的值。因此和精化与删除有关的问题也适用于这里。
清单 15. 检索 TXLifeRequest ID 和人员列表
XQuery
for $trans in //TXLifeRequest
for $tid in $trans/@id
return <TX>{$tid}
{ for $P in $trans//Person return $P}</TX>
|
结果
<result>
<TX id="TXLifeRequest1001">
<Person>
<FirstName>Alan</FirstName>
<LastName>Bird</LastName>
<Gender>MALE</Gender>
</Person>
</TX>
<TX id="TXLifeRequest1002">
<Person>
<fName>Carl</fName>
<lName>Devon</lName>
<Gender>MALE</Gender>
</Person>
</TX>
</result>
|
|
清单 16. 检索 TXLifeRequest ID 和人员列表
XQuery
for $trans in //TXLifeRequest
for $tid in $trans/@id
return <TX>{$tid}
{ for $P in $trans//Person/LastName return $P}
{ for $P in $trans//Person/lName return $P}
</TX>
|
结果
<result>
<TX id="TXLifeRequest1001">
<LastName>Bird</LastName>
</TX>
<TX id="TXLifeRequest1002">
<lName>Devon</lName>
</TX>
</result>
|
|
重新编号
也可以指定元素的基数
— 即在同一个父元素中一个元素出现一次还是多次。从一到多将使结果中出现同一元素的多个实例。从多到一更简单,仅仅减少了结果的基数。清单 17 所示新文档实例中允许三个电话号码,而旧文档中只有一个。检索参与者电话号码的查询(类似于 清单 12)对旧模式返回一个电话号码,新模式返回多个电话号码。
清单 17. 模式变化的文档实例:改变基数和类型
旧模式的文档实例
<TXLife>
<TXLifeRequest id="TXLifeRequest1001">
<TransRefGUID>2006-0712-1001</TransRefGUID>
<TransType tc="103">Schema Evolution</TransType>
<OLifE>
<Party id="ID1101">
<Person>
<FirstName>Alan</FirstName>
<LastName>Birch</LastName>
<Gender>MALE</Gender>
<Phone>212 123 4567</Phone>
</Person>
<Address>
<Line1>202 W 101st St</Line1>
<City>New York</City>
<AddressStateTC tc="60">NY</AddressStateTC>
<Zip>10025</Zip>
</Address>
</Party>
</OLifE>
</TXLifeRequest>
</TXLife>
|
新模式的文档实例
<TXLife>
<TXLifeRequest id="TXLifeRequest1002">
<TransRefGUID>2006-0712-1001</TransRefGUID>
<TransType tc="103">Schema Evolution</TransType>
<OLifE>
<Party id="ID1103">
<Person>
<FirstName>Carl</FirstName>
<LastName>Devon</LastName>
<Gender>MALE</Gender>
<Phone>212 234 4567</Phone>
<Phone>212 234 5678</Phone>
<Phone>212 234 6789</Phone>
</Person>
<Address>
<Line1>80 W 109th St</Line1>
<City>New York</City>
<AddressStateTC tc="60">NY</AddressStateTC>
<Zip>10025-2638</Zip>
</Party>
</OLifE>
</TXLifeRequest>
</TXLife>
|
|
改变类型
从可比性和对查询的影响来看,这种变化最有挑战性,因为要保持查询仍然有效必须遵循特定的过程。比如,假设 where 子句对值 v 进行整数比较,而后来 v 的类型变成了 string。这种情况下需要强制类型转换函数(如 $elem cast as xs:integer)来保持查询的有效性。
这种变化还包括扩展元素和通过刻面限制元素。约束刻面包括 length、minLength、maxLength、pattern、enumeration、whiteSpace、maxInclusive、maxExclusive、minExclusive、minInclusive、totalDigits 和 fractionDigits。从查询公式的角度来看,这些变化影响带有比较约束的查询。此外,受到影响的类型的结果也不同。比如,清单 17 将邮政代码范型从 <pattern value='[0-9]{5}'/> 变为 <pattern value='[0-9]{5}(-[0-9]{4})?'/>
— 即增加了可选的四位数字扩展。检索元素内容的一半查询,如 清单 18 所示,没有什么问题。另一方面,比较约束很容易破坏查询,如 清单 19 所示。
默认值
模式验证为文档实例中省略的属性和空白元素添加默认值。如果数据类型相同,改变默认值对查询公式没有影响,但是影响这些值的查询结果。还要特别注意使用比较约束检索默认值以外的所有数据的查询。这种情况下对不同模式的文档应使用不同的查询访问文档。
清单 18. 检索 TXLifeRequest ID 和地址列表
XQuery
for $trans in //TXLifeRequest
for $tid in $trans/@id return <TX>{$tid}
{ for $P in $trans//Address return $P}</TX>
|
结果
<result>
<TX id="TXLifeRequest1001">
<Address><Line1>202 W 101st At</Line1>
<City>New York</City>
<AddressStateTC tc="60">NY</AddressStateTC>
<Zip>10025</Zip></Address>
</TX>
<TX id="TXLifeRequest1003">
<Address> <Line1>80 W 109th St </Line1>
<City>New York</City>
<AddressStateTC tc="60">NY</AddressStateTC>
<Zip>10025-2638</Zip></Address>
</TX>
</result>
|
|
清单 19. 检索邮政编码为 10025 的 TXLifeRequest ID 地址列表
XQuery
for $trans in //TXLifeRequest
for $tid in $trans/@id
return
<TX>{$tid}
{ for $P in $trans//Address
where Zip="10025"
return $P}
</TX>
|
结果
<result>
<TX id="TXLifeRequest1001">
<Address> <Line1>202 W 101st St</Line1>
<City>New York</City>
<AddressStateTC tc="60">NY</AddressStateTC>
<Zip>10025</Zip>
</Address>
</TX>
<TX id="TXLifeRequest1003"></TX>
</result>
|
|
名称空间
在 XML 模式演化的过程中,有时候用不同的名称空间表示不同的模式版本。如果文档名称空间和查询中指定的不同,对名称空间敏感的查询将返回空的结果。如果希望返回相同的结果,查询中的名称空间应使用通配符。
改变顺序
一般来说,多数 XML 查询对顺序不敏感。但是,XML 查询中有时候使用位置谓词,比如:
这种情况下,查询可能返回错误的结果,对应用程序的功能产生严重影响。
管理 XML 模式演化的基本原则
这一节讨论控制模式演化的实际问题,并提供出一组用于编写跨模式版本查询的指导原则。
控制模式变化
要保证查询不受模式演化的影响,一个相关问题是如何控制模式演化本身。如何管理 XML 模式演化有很多因素影响,比如:
- 谁控制模式的变化
- 谁控制应用程序语义(比如查询、更新和模式验证)
- 允许什么类型的模式变化
- 允许什么类型的应用程序(和查询)
表 3 列举了这些问题的不同答案以及相应的例子。
在这四种角色中,XML 数据和应用程序架构师对于如何设计模式变化和应用程序来管理模式演化具有最大的自由度。而与之相反的另一端,一般 XML 用户对于管理模式演化无能为力。夹在中间的应用程序架构师可以控制如何编写应用程序中的查询。一般来说,他们需要确定什么时候需要中断应用程序以及如何中断应用程序中的查询。应用程序中断可能有以下几种情况:
- 应用程序跨所有版本的 XML 模式工作
- 大的版本变化导致程序中断
- 较小的版本变化导致程序中断
表 3. 控制应用程序和模式变化的不同选项
|
| 能够控制模式变化 | 不能控制模式变化 |
|---|
| 控制应用程序 |
XML 数据和应用程序架构师,设计和开发 XML 模式和应用程序。
|
XML 应用程序架构师,设计和开发使用符合某种标准 XML 模式(不是自己设计的)的 XML 数据的应用程序。
|
|---|
| 不能控制应用程序 |
XML 数据架构师或者标准化组织,设计 XML 模式。
|
XML 用户,运行现成的针对标准 XML 格式的应用程序(比如 XML 模式验证)。
|
|---|
类似的,对不同模式执行查询可能得到下面的结果:
- 查询返回正确的结果(正确性由应用程序的语义决定)
- 查询没有结果
- 查询返回错误的结果
如果应用程序遇到新模式版本的 XML 文档,应用程序架构师需要决定要哪种结果,以及如何处理这种结果。
一般来说,对一般信息(如消息标识符和社会安全号码)的查询应该对所有模式版本都能返回正确的结果。高度依赖重大版本变化的应用程序,应用程序应该不返回结果或者检查重大版本变化并标记异常。类似的,对小版本变化敏感的应用程序,查询应该不返回结果或者标记异常。一般应避免不检查版本变化并允许处理错误的结果。
这就提出了什么是重要和细微的版本变化 — 这个问题部分取决于应用程序语义。但是,因为应用程序需要检查重要或细微版本变化,架构师需要考虑如何对变动编码。换句话说,如何编码版本以及新模式改动是大是小取决于 XML 数据架构师,他需要考虑两方面的因素。首先是如何编码模式版本的问题,通常有两种方法:
- 用名称空间编码版本
- 在 XML 文档中包含明确的 version 元素或属性
每种方法各有长短。
其次,XML 数据架构师需要对 XML 数据的不同应用程序和使用者有所了解(比如如何处理 XML 文档),以便决定模式的变化是大还是小。
编写跨越不同模式版本的查询
本文假设 Web 应用程序或者服务必须支持所有 XML 模式版本,查询必须对各种版本都能返回正确的结果。在这种情况下,根据前面的示例,我们设计了下列原则以便保证查询适用于不同的模式版本。
-
不要在层次的中间增加必须的元素。如果需要,查询可使用 XPath 中的祖先或后代轴,否则就不能用于新的模式。
-
类似的,不要从层次结构的中间删除必须的元素(或属性)。
-
如果查询涉及到顺序谓词,不要改变模式中的元素顺序。
-
如果查询是强类型的或者需要进行值比较,不要改变原子类型(string、integer 等)。
-
如果任何查询引用了元素名称,不要改变元素名称。如果必须修改,则考虑在应用程序中增加同义词控制,保证新旧名称指向同一个元素。
-
类似的,不要改变被查询引用的元素的类型或者刻面。如果必须改变类型,必须同时修改查询,增加相应的强制类型转换函数。
-
如果使用名称空间区分模式版本,应考虑在查询中的名称空间约定中增加通配符(*)。
-
需要特别注意某些 XPath 函数如 exist ,因为它们要求具有特定元素的版本才能进行查询计算。这类函数应小心使用。
-
查询组合或者分解的元素返回结构不同的结果。一方面,如果组合或分解元素用于比较(在 where 子句中)或者路径表达式,查询可能无法用于所有模式版本的文档实例。审查访问组合或分解元素的查询以保证得到适当的结果。
结束语
本文提出了 XML 模式演化过程中变动的扩展分类。我们详细讨论了模式演化对验证、查询公式和结果的影响。在此基础上,我们提出了一组能够保持跨模式版本查询的基本原则。本文并没有介绍所有可能的情形,而是列举 XML 设计人员在模式演化过程中遇到的最常见的情形。此外,有些情况下,查询不应该跨大的版本变动工作。本文中没有涉及到这些情况,将在以后的文章探讨。
参考资料 学习
获得产品和技术
讨论
作者简介  | 
|  | Mirella Moro 是巴西 Universidade Federal do Rio Grande do Sul 的一位研究员。她从加州大学河滨分校获得了博士学位,从 Universidade Federal do Rio Grande do Sul 获得了硕士和学士学位。她曾于 2006 年夏天在 IBM T.J. Watson Research Center 实习。 |
 | 
|  | Susan Malaika 是 IBM Information Management Group(属于 IBM Software Group)的高级技术职员。她主要研究 XML、Web 和数据库。她在 Global Grid Forum 上提出了网格环境下的数据支持标准。她不仅仅是 IBM 产品软件开发人员,同时也是 Internet 专家、数据分析师、应用程序设计师和开发者。她与人合作出版了关于 Web 的专著,发表了关于事务处理和 XML 的文章。她是 IBM Academy of Technology 的成员。 |
 | 
|  | Lipyeow Lim 是 IBM T. J. Watson Research Center 的研究人员。他从 Duke University in Durham, North Carolina 获得了博士学位。他的研究方向是数据库技术领域 — 特别是 XML 数据库、统计信息采集和查询优化。 |
对本文的评价
|