级别: 初级 柴晓路 (fennivel@uddi-china.org), Chief System Architect
2001 年 6 月 01 日 本文针对计算机系统间数据层深入广泛的互操作需要,基于企业级应用中XML模式与关系模式之间的数据转换,提出了一种规则驱动的在XML模式与关系模式之间进行数据转换的方法。该方法极大地抽取了转换的共性,采用转换脚本作为转换特性的描述方法,实现了一个低线性代价的星状数据交换模式,同时为具体用户带来定制转换的简易性。
引言
W3C在1998年制订了XML的标准,启动了整个Internet环境下的信息标准化的进程。两年间,适应于各行业需求的XML
Application纷纷被制订。而这些XML
Application也如同网状的Internet一样在整个应用体系中呈网状分布。这些交换标准主要分这样几类:1)
为实现跨行业业务而建立的体系式交换标准,如xCBL、cXML、ebXML等;2)
应垂直行业内信息交换需要而建立的交换标准,如SML、adXML、MEDoc等;3)
通用的、适用企业内部某一领域的专业交换标准,如CIML、OCF、FIX;4)
软件应用领域的专有信息描述标准,如Wf-XML、XEDI、UIML等。
对任意一个企业级或门户级应用而言,它不可避免地需要根据多个交换/描述标准提供数据接口,而且应当为潜在的交换/描述标准预留接口。同时随着系统的进化、自动化程度的提高,数据的一次转换流程将不局限于一个交换/描述标准,在很多情况下需要涉及两个或多个交换/描述标准,而且所有通过数据界面获得的数据必须保存入数据库。例如某个生产汽车的厂商使用AIAG的行业交换标准获得配件商的信息,然后使用CommerceOne的xCBL与该配件商完成商务交易,最后又要使用FIX与银行进行财务信息的交换,在这种应用情况下,某些数据(比如配件价格)就需要从AIAG的文档实例转到xCBL的文档实例,并最后转到FIX的文档实例,而所有的这些数据又必须保存在数据库中以便应用程序进行处理。若为每两个存储格式构筑转换应用,是一项复杂度呈指数增长的工作。如何有效地线性地解决这一问题,这对数据交换技术提出了新的挑战。
本文针对这一问题,利用交换技术的精髓:集中与标准,提出了一种基于XML数据环境的规则驱动的数据交换方法,该方法利用关系模式为元层次上唯一交换标准,实现了元层次上的星状的线性代价的交换。本文的其余部分安排如下:第二节介绍国际研究应用领域的相关工作;第三节讨论交换的精髓:集中与标准;第四节详细阐述使用关系模式作为唯一元层次交换标准的规则驱动的数据交换方法;第五节则给出了本文的结论。
相关的工作
系统间深层次的广泛协作是Internet时代的重要发展方向,作为系统间深层次协同工作的基础层次:数据层的协同工作正是各大软件生产商、数据交换标准化组织及新兴软件公司的一个重要研究方向。其中Microsoft的Biztalk
Server 2000提供了从XML Schema到XML
Schema的映射工具,但是他无法解决广度的实体关系与深度的实体关系的映射,更不用谈从XML
Schema到RDB Schema了。Jayavel
在他的VLDB'99的论文[1]中给出了一个将任意XML文档转换成关系模式的方法,但目标关系模式是动态生成的,与我们的目标不符,而且该关系模式的质量较差,无法表示真正的ER关系。IBM
UDB 7.1的XML
Extender[3]提供了DAD作为从关系模式到XML模式互相转换的规则定义,但功能不够,不支持递归和引用,无法描述复杂的转换。而作者在硕士毕业论文中描述构建基于元数据体系的数据交换模型,对XML数据到关系数据的转换做了一点初步研究,但同样不具备足够的通用性,本文就是在我的毕业论文的相关内容的基础上的深入。
交换的精髓:集中与标准
在数据交换领域中,没有标准的部落式交换的代价是高昂的,相同的数据分析处理模块在很多应用中被重复地撰写,可能只是为了将某一数据源的数据转换到各个不同的目标数据源中去。由于没有中间标准,各个系统的实现人员也几乎没有可能将代码重用,昂贵的数据交换代价使得数据源只能散乱孤立地存在。前面描述的这一状况在XML出现之前,在绝大多数的应用领域里都是如此,即使在某些局部领域,如传统的电子商务领域,有EDI这么一种商务信息的交换标准,可是在更广泛一点的领域,仍然没有一个全域统一的交换体系。而XML作为一种数据格式描述的元语言标准,从出现以后,就不断地被应用到各种不同的数据交换领域中去。使用XML制订的应用领域的交换标准的出现,使得在各个应用领域中都形成了交换的优化模式:星状交换(参阅图1)。其中每个系统都将其内部的数据转换成行业标准的基于XML的数据格式用于系统间的交换。
交换的精髓就在于集中和标准,集中的星状交换模式带来了线性的交换代价,而交换标准的确立又使得集中的星状交换真正成为可能。
Figure 1. 星状交换模式
随着XML的广泛应用,系统与系统间的联系更为紧密。而同时,企业级应用往往会有多个子系统所组成,每个子系统涉及的行业数据领域可能各不相同,如何建立一个内聚高耦合、外联一体化的企业级应用,这向以电子商务为代表的前沿企业商务应用提出了挑战。
我们分析了目前企业级应用中涉及的数据类型:存放在RDB中的数据、按各种XML
Application标注的数据、EDI格式的数据、存放在LDAP及其他信息组织形式中的数据。前三类是信息的主要部分,由于已经有EDI数据的XML组织方式XEDI的存在,所以从逻辑上我们可以进一层,主要面对这样两类数据:关系模式下的数据和XML模式下的数据。针对这一数据环境,遵循交换的核心思想:集中和标准,我们设计了一个面向模式的规则驱动的数据交换方法,该方法以关系模式为交换标准,所有XML描述格式都通过关系模式这一中间标准完成交换。需要注意的是由于这是一个定义在元层次上的交换方法,关系模式端涉及的具体关系可以是不预先确定,而是在运行时定义的。由于是构筑在星状体系上的交换模式,所有的交换单体彼此是独立的、相互无关的。综合前两点,我们可以认为,星状体系上的每条边在转换逻辑上是彼此正交的。如果在实现逻辑上也是正交的,那么在具体应用中仍然会面临很大的问题:1)
各个企业级应用所面临的关系模式各不相同;2)
实现一个具体的XML模式到关系模式的数据转换需要涉及较为复杂的XML格式分析处理及相应的数据库操作及有效性校验。开发代价是n*m*C(n和m分别代表XML模式和关系模式的数量),C代表的是有经验的程序员在较大的开发代价下完成的转换应用程序。如果能将C的代价大大减小,成为一般开发人员经过相当短的时间就可以掌握并实现的转换应用,那么这一体系才是真正有效的,才能真正被广泛应用。我们通过对XML的数据模型与关系模型的特征的考察,认为两者转换的实质是1)
从XML中的数据(存在方式可以是Content、属性值、元素名等)到关系模式中字段的映射;和2)
从XML中数据的相互位置关系到关系模式中元组与元组的关系及元组与字段的关系的映射。通过实验,我们实现了将共性的映射机制抽取成转换程序,而具体的映射规则使用我们自己定义的XML
Application:XPDL(XLanguage Processing Definition
Language)来标注,作为转换程序的一个脚本,以完成一个具体的转换应用。其模式可以参阅图2。这样,对于每一个具体的转换应用,开发人员只需要撰写一个转换规则脚本,能够很快地完成应用实现。这样一种脚本插件的机制在作者的另一篇论文XML
Arouse the Web Architecture Revolution(LNCS
1749)[2]中有较详细描述,有兴趣的读者可参阅该文。在下一节中,将详细叙述该转换规则脚本XPDL的结构和工作机制。
Figure 2. 转换方法示意
XML模式与关系模式的相互转换
本文讨论的XML模式与关系模式的转换的核心与实质就是按XPDL编写的转换规则和转换规则的执行解释方法,下面就依次分别介绍从XML模式到关系模式的转换规则的组成部分和执行方法以及从关系模式到XML模式的转换规则的组成部分和执行方法。由于篇幅限制,下面的内容比较简略,如有疑问,敬请与作者联系。
一个完成XML模式到关系模式转换的转换规则脚本由关系模式的定义和XML模式到关系模式转换规则的定义组成,而完成关系模式到XML模式转换的转换规则脚本由关系模式的定义和关系模式到XML模式转换规则的定义组成。之所以没有在脚本中定义XML模式,是因为转换脚本是使用XML撰写的,因此XML模式部分和转换规则部分相融合。
关系模式定义
下面是一个关系模式定义的例子,关系模式的定义虽然在转换算法中的地位并不重要(从某种程度而言,本文中介绍的算法完全可以脱离关系模式,完全可以面向LDAP等非关系的数据源,也就是可以将算法进一步泛化),但后面所讲的转换规则完全依赖该定义,因此在这里给出一个较简单的说明性定义。
<DataSchemaDefinition>
<DataSource id="iCategoryData" type="ODBC" sourcename="iCatSRC" username="sa" password="" />
<DataSchema>
<Entity id="category" datasource="iCategoryData">
<Structure>
<Field id="nodeid" type="char" length="10" cannull="no" primary_key="yes" />
<Field id="fathernodeid" type="char" length="10" cannull="no"/>
<Field id="rootnodeid" type="char" length="10" cannull="no"/>
<Field id="groupname" type="char" length="50" />
</Structure>
<Constrain>
<Reference field="fathernodeid" refentity="category" reffield="nodeid">
<ExceptionValue value="0" />
</Reference>
<Reference field="rootnodeid" refentity="category" reffield="nodeid">
<ExceptionValue value="0" />
</Reference>
</Constrain>
</Entity>
<Entity id="Item" datasource="iCategoryData">
<Structure>
<Field id="personid" type="char" length="10" cannull="no" primary_key="yes" />
<Field id="groupid" type="char" length="10" cannull="no" />
<Field id="personname" type="char" length="50" />
<Field id="email" type="char" length="100" />
</Structure>
<Constrain>
<Reference field="groupid" refentity="category" reffield="nodeid" />
</Constrain>
</Entity>
</DataSchema>
</DataSchemaDefinition>
|
一个关系模式的定义分两部分:数据源(Data
Source)定义和实体(包括关系实体)的定义。数据源的定义不外乎ODBC/JDBC/BDE等几种,大家可以看到右图中是通过一个DataSource的元素来标注的,定义它的目的在于转换程序的跨平台的通用性。
实体定义包含两部分:结构定义和约束定义。结构定义类似关系数据库的表定义,包含对每个字段的类型、长度等的定义。约束定义则主要包含对字段的外键和引用的约束定义。例如<Field
id="personid" type="char" length="10" cannull="no"
primary_key="yes"
/>是一个字段定义,表示在当前实体内有这么一个字段:字段标识为personid、类型为char、长度为10、不允许空值、是主键字段。而<Reference
field="fathernodeid" refentity="category" reffield="nodeid">
<ExceptionValue
value="0"/></Reference>则表示当前实体内字段fathernodeid是一个引用属性、引用的是实体category、对应标识是category的字段nodeid,其中有一个例外值,fathernodeid可以取值为0,而0不是一个引用,是一个例外。
XML模式到关系模式转换规则(X2RConversion)的定义
XML模式到关系模式的转换的目标,是将某一种XML
Schema定义好的XML文档中的Content部分、属性值部分转换成关系模式中的某个元组的某个字段的值,而将他们之间的位置关系转换成关系模式中的外键等应用关系。之所以在XPDL的第一版中没有支持将元素名和属性名转换成字段值,是因为我们在具体实验中考察了目前大部分商用XML
Application的定义,发现几乎没有这样的需求。下面是一个转换规则的定义,它是承继图3定义的关系模式的。而在转换规则之后的则是待转换XML文档的模式定义的片段(这里使用了DTD)。在我们的交换体系中,从XML模式到转换规则定义是满射。
<X2RConversion>
<Entrance>
<Record entity="category" id="st_category" path=".department">
<Default field="fathernodeid" value="0" />
<Node path="#id" field="nodeid" />
<Node path=".name" field="groupname" />
<Node path="#fatherid" field="fathernodeid" />
<Node path="#rootid" field="rootnodeid" />
<Reference field="rootnodeid" reftype="entity" refvalue="category[nodeid]" refpos="0" />
<Record entity="category" id="run_category" path=".department">
<Node path="#id" field="nodeid" />
<Node path=".name" field="groupname" />
<Node path="#fatherid" field="fathernodeid"/>
<Node path="#rootid" field="rootnodeid" />
<Reference field="fathernodeid" reftype="entity" refvalue="category[nodeid]" refpos="-2" />
<Reference field="rootnodeid" reftype="entity" refvalue="category[nodeid]" refpos="0" />
<Record refid="run_category" />
<Record refid="leaf_item" />
</Record>
<Record entity="item" id="leaf_item" path=".person">
<Node path="#id" field="personid" />
<Node path=".name" field="personname" />
<Node path=".contact.email" field="email" />
<Reference field="groupid" reftype="entity" refvalue="category[nodeid]" refpos="-1" />
</Record>
</Record>
</Entrance>
</X2RConversion>
|
<!ELEMENT department (name,department*,person*)>
<!ATTLIST department id ID #REQUIRED>
<!ATTLIST department fatherid IDREF #IMPLIED>
<!ATTLIST department fatherid IDREF #IMPLIED>
<!ELEMENT person (name, contact)>
<!ATTLIST person id ID #REQUIRED>
<!ATTLIST person groupid IDREF #IMPLIED>
<!ELEMENT contact (email, phone)>
|
转换的基本算法是广度优先遍历待转换的XML文档的DOM树,对于每个结点而言,从根到该结点的路径作为其转换标识,如前面描述的转换规则中第一个Record的路径就是X2Rconversion.Entrance.
Record(本文使用的例子是将部门和人员的XML描述转换为category和item的关系存储,关系定义可参见前面的关系模式定义)。每一个转换入口是一个转换标识后缀,当某一转换入口转换标识后缀匹配当前结点的转换标识,则启动当前转换入口对应的转换规则。所有的转换入口都定义在Entrance元素内。每一个转换规则都是由一个Record元素开始的,一个Record元素的下层元素表示了其对应的元组的新记录的创建、数据的转换规则及其关联元组的的新记录的创建、数据的转换规则,也就是说Record元素是可嵌套的。
path是转换规则的一个重要概念,在转换入口定义的path是转换入口的转换标识后缀,如前面描述的转换规则中的<Record
entity="category" id="st_category"
path=".department">是一个转换入口规则根元素,".department"就是转换标识后缀,当在广度遍历文档DOM树时,当前结点的路径后缀是".department"时就启动该转换规则。除转换入口处外,下层的元素中的path都是相对值,添加到上层的完全值后就成为该元素的完全值。如第一个Node的path完全值就是".department#id"(在path中有两种分隔符,"."表示后面跟的是元素名,"#"表示后面跟的是属性名),而第二个Record的path完全值则为".department.department"。
Default元素对应一个字段的默认值赋予,如前面描述的转换规则的第一个Default元素是为根category的fathernodeid赋例外值0。Node元素总对应一个字段的值的转换,当其自身的path标识了一个元素时,则将元素的内容赋给指定的字段(紧接着的上层Record对应的元组的字段,该元组由entity属性定义),而当其自身的path标识了一个属性时,则将属性的值赋给指定的字段。
Reference元素是转换规则中的重要部分,负责将元素的位置转换为实体的联系。在XPDL的第一版中仅支持在同一路径中的实体的联系,目前看来这样的支持对大多数应用是完全足够了。Reference元素的属性有:field指明当前元组的引用(或外键)字段;reftype指名引用的对象类型,目前支持两种:entity和record,分别表示引用的是元组(由entity标识)还是转换规则中定义的记录转换(由Record的id标识);refvalue指明的是引用对象的名;而refpos指明的是引用对象在路径中的位置(在路径中可能有同一对象的递归出现,这里的位置是在路径中相同对象中的位置,而不是路径中所有对象的位置),当refpos的值有符号的时候表示相对位置,如-1表示紧接着的上一个对象,而无符号是表示绝对位置,如0表示起始的那个对象。
例如:<Reference field="rootnodeid" reftype="entity"
refvalue="category[nodeid]" refpos="0"
/>表示rootnodeid引用起始的category元组所对应记录的nodeid,即记录了根结点id。这一个引用与<Reference
field="rootnodeid" reftype="record" refvalue="st_category[nodeid]"
refpos="0"
/>在本例中是等价的,因为起始category一定是使用st_category标识的。而<Reference
field="fathernodeid" reftype="entity" refvalue="category[nodeid]"
refpos="-2"
/>则是描述了如何将父子关系转换入元组的fathernodeid中保存。
非转换入口的Record的path一样是要加在上层元素的path的完全值之后构成该Record的完全值的,由该值确定转换位置后,转换操作同转换入口的Record。本质上,一个转换入口标识的转换规则是挑出以转换入口为根的一棵子树并保存入对应的元组中。而转换规则并非是唯一的,例如前面的前面描述的转换规则完全可以被改写为更简练的转换规则,具体见下面的代码,Record的引用(使用refid),就如同将被引用的Record描述(包括下层所有元素)插入到引用位置一样,完全等价。
<X2RConversion>
<Entrance>
<Record entity="category" id="node_category" path=".department">
<Default field="fathernodeid" value="0" />
<Node path="#id" field="nodeid" />
<Node path=".name" field="groupname" />
<Node path="#fatherid" field="fathernodeid" />
<Node path="#rootid" field="rootnodeid" />
<Reference field="fathernodeid" reftype="entity" refvalue="category[nodeid]" refpos="-2" />
<Reference field="rootnodeid" reftype="entity" refvalue="category[nodeid]" refpos="0" />
<Record refid="node_category" />
<Record entity="item" id="leaf_item" path=".person">
<Node path="#id" field="personid" />
<Node path=".name" field="personname" />
<Node path=".contact.email" field="email" />
<Reference field="groupid" reftype="entity" refvalue="category[nodeid]" refpos="-1" />
</Record>
</Record>
</Entrance>
</X2RConversion>
|
此外,转换还将遵循以下原则:任意两个Record转换实例的转换位置所对应的元素绝不相同,也就是说如果一个元素被一个Record标定被执行转换后,他就不会被另一个Record标定并转换了,但被Node标定的元素并不受该限制,也就是说在转换算法中只记住每个Record实例的执行位置;而在同层规则执行顺序上,是按Default元素、Node元素、Reference元素、Record元素的次序的,一个次序在后的有效操作是可以覆盖次序在前的有效操作的。
关系模式到XML模式的转换规则(R2XConversion)的定义
从关系模式到XML模式的转换实质上是一个将一个预先定义好的视图运行并将当前视图内容转化成XML格式显示,在具体实现上我们是将格式和视图定义融合在一起。在关系模式到XML模式的转换中,关系模式定义段中的entity可以对应一个SQL查询语句,也就是使用SQL语句代替原先在id中指明的表名,所有的数据准备基本在关系模式定义段已经完成。下面是一个关系模式到XML模式的转换规则的示例。它的执行是通过深度编历转换规则,逐个分枝拓展创建,并最终完成整个XML文档DOM树的创建。同样,其中仅支持一条路径扩展出的子树中的相对位置的关联转化。
<R2XConversion>
<XNode id="root" type="element" name="Root" state="static">
<XNode id="root_category" type="element" name="department" state="bindrecord" entity="category">
<Condition operator="equal">
<Operand seq="1" reftype="entity" refvalue="category[fathernodeid]" refpos="-1"/>
<Operand seq="2" reftype="value" refvalue="0" />
</Condition>
<XNode type="element" name="name" state="static">
<XNode type="text" name="_text" reftype="entity" refvalue="category[groupname]" refpos="-1" />
</XNode>
<XNode type="attribute" name="id" reftype="entity" refvalue="category[nodeid]" refpos="-1" />
<XNode id="node_category" type="element" name="department" state="bindrecord" entity="category">
<Condition operator="equal">
<Operand seq="1" reftype="entity" refvalue="category[fathernodeid]" refpos="-1" />
<Operand seq="2" reftype="entity" refvalue="category[nodeid]" refpos="-2" />
</Condition>
<XNode type="element" name="name" state="static">
<XNode type="text" name="_text" state="bindfield" reftype="entity"
refvalue="category[groupname]" refpos="-1" />
</XNode>
<XNode type="attribute" name="id" state="bindfield" reftype="entity"
refvalue="category[nodeid]" refpos="-1" />
<XNode refid="node_category" />
</XNode>
</XNode>
</XNode>
</R2XConversion>
|
在关系模式到XML模式的转换规则中,XNode是最主要的一个元素,它的作用类似DOM中的DOMNode,生成的也是DOM中的DOMNode,它的每一次触发都将生成指定类型的DOMNode的一个实例。
目前XNode支持三种状态:static静态的单触发的固定结点;bindrecord动态绑定元组记录的多触发(由条件Condition段过滤)
结点;bindfield动态绑定记录字段的单触发结点。XNode是来定义目标XML文档的基本结构的。而Condition用于在多触发结点过滤数据源的绑定数据,每一个Condition元素描述了一个条件表达式。另外其中的所有reftype/refvalue/refpos等与X2Rconversion中的含义是一致的。
上面的例子的执行结果就是将前面描述到的将XML模式转换到关系模式的例子中转换目标中的category元组转换回XML文档。其中最外层的XNode定义了文档根Root,下一个XNode选取了所有父结点为0的category中的记录生成该层的多个department元素,以id:node_category标识的XNode则是递归生成下层的department元素。而针对category[groupname]和category
[nodeid]则分别是text和attribute类型的XNode。
对于X2RConversion和R2XConversion的规则定义,由于受篇幅限制,这里只能做描述性的说明,待整个转换系统完成最后完善,我们会给出完整的规范定义,在这里就不详细说明了。
有了从XML模式到关系模式的转换和从关系模式到XML模式的转换,我们就可以利用这两个工具完成任意XML模式到任意XML模式的转换了:XML模式←→关系模式←→XML模式。
结论
本文的方式实现了任意XML模式之间,任意XML模式与任意关系模式之间的数据转换,将转换中具有个体特征化的部分使用转换规则来定义,使一般用户可以方便轻松地掌握并使用,同时采用该机制能更有效地保证数据的准确性和模式的一致性。我们以后的工作是进一步增强转换规则的能力和转换程序的效率,使该转换方法获得更高的通用性和适用性。
参考资料
- Jayavel Shanmugasundaram, Kristin Rufte, Gang He, et.al.,
Relational Databases for Querying XML Documents: Limitations and
Opportunities, VLDB'99, 1999
- 柴晓路, 曹晶, 高永勤, 施伯乐, XML Arouse the Web Architecture
Revolution, Lecture Notes in Computer Science (LNCS), Volume 1749,
1999
- DB2 XML Extender Administration and Programming, IBM, 2000
- XML Schema Part 1: Structures, W3C Working Draft, 2000
- XSL Transformations Version 1.0, W3C Recommendation, 1999
关于作者  | 
|  |
柴晓路:
上海得易电子商务技术有限公司(
DealEasy)首席系统架构师、XML技术顾问。2000年获复旦大学计算机科学硕士学位,曾在国际计算机科学学术会议(ICSC)、亚太区XML技术研讨会(XML
Asia/Pacific'99)、中国XML技术研讨会(北京)、计算机科学期刊等各类国际、国内重要会议与期刊上发表论文多篇。专长于基于XML的系统集成和数据交换的技术研究,同时对数据库、面向对象技术及CSCW等技术比较擅长。2001年加入
UDDI Advisor
Group,参与了UDDI Specification V2的开发。目前作为
UDDI-China.org的主要核心成员参与UDDI-China.org的核心技术工作。UDDI-China.org是在UDDI.org和DealEasy
Technology的支持下在2001年6月发布的UDDI技术站点。
|
对本文的评价
|