删除
清单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查询中有时候使用位置谓词,比如:
//OLifE/party[2]
这种情况下,查询可能返回错误的结果,对应用程序的功能产生严重影响。
管理XML模式演化的基本原则
这一节讨论控制模式演化的实际问题,并提供出一组用于编写跨模式版本查询的指导原则。
控制模式变化
要保证查询不受模式演化的影响,一个相关问题是如何控制模式演化本身。如何管理 XML 模式演化有很多因素影响,比如:
·谁控制模式的变化
·谁控制应用程序语义(比如查询、更新和模式验证)
·允许什么类型的模式变化
·允许什么类型的应用程序(和查询)
表3列举了这些问题的不同答案以及相应的例子。
在这四种角色中,XML数据和应用程序架构师对于如何设计模式变化和应用程序来管理模式演化具有最大的自由度。而与之相反的另一端,一般XML用户对于管理模式演化无能为力。夹在中间的应用程序架构师可以控制如何编写应用程序中的查询。一般来说,他们需要确定什么时候需要中断应用程序以及如何中断应用程序中的查询。应用程序中断可能有以下几种情况:
·应用程序跨所有版本的XML模式工作
·大的版本变化导致程序中断
·较小的版本变化导致程序中断
表3. 控制应用程序和模式变化的不同选项
类似的,对不同模式执行查询可能得到下面的结果:
·查询返回正确的结果(正确性由应用程序的语义决定)
·查询没有结果
·查询返回错误的结果
如果应用程序遇到新模式版本的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数据库、统计信息采集和查询优化。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
相关推荐
-
BEST:SOAP/XML和REST的替代方案
虽然拥有大量的机架服务器,以及大量软件开发人员的组织,基于web和集成服务的SOAP和REST很适合他们,但也会出现问题。
-
Spring 烂!差!
有些人可能对Spring的第一印象不太好,它真的很烂,很差吗,也许这只是你的一种偏见,它也有是自己的优点的。
-
基于SOA架构的业务安全性研究
SOA在提供价值链上企业之间信息共享和业务流程自动化的同时,也给业务信息安全带来了负面影响,且存在安全隐患,这些你知道吗?
-
Java读取配置文件的几种方法
在现实工作中,我们常常需要保存一些系统配置信息,大家一般都会选择配置文件来完成,那么在Java怎样读取配置文件呢?