IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Information Management  >

developerWorks 图书频道: DB2 V9/9.5 高级应用开发,第 4 章

DB2 V9 中的 pureXML

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 初级

管松, 内容管理产品(Content Manager)开发经理, IBM
肖振春, 高级软件工程师, IBM
张建伟, 高级软件工程师, IBM
林光国, 高级软件工程师, IBM
王东明, 高级软件工程师, IBM
闫庆宏, 软件工程师, IBM
李尚强, 高级软件工程师, IBM
王庆法, 高级软件工程师, IBM

2009 年 5 月 11 日

本书详尽地为大家介绍了一系列 DB2 应用开发的方法及丰富的实例。从嵌入式 SQL 应用开发、各种 DB2 调用式接口的应用模式、DB2 服务端的应用开发、XML 层次型数据的应用,至 DB2 性能分析及调整,深入浅出,见解精辟。无论是用于教学还是对于从事 DB2 应用开发的专业人士,本书均是一本不可或缺的工具书。
在此我们推出了本书的 前言、第 1 章和第 4 章供大家在线浏览。更多推荐书籍请访问 developerWorks 图书频道

4.1 XML 数据库

DB2 从 v9 开始引入了 pureXML 技术,能够提供对 XML 数据的原生存储、索引、Schema 校验、查询,以及更新支持,并且有机地融合原生 XML 数据库与成熟的关系数据库。本章将从理论和实践两个层面对此加以介绍。

4.1.1 XML 基础

1 . XML

XML 可扩展标记语言经过多年的发展,已经成为软件领域数据交换的行业标准,且迅速的向很多 IT 的纵深领域发展。 XML 与数据库的融合是自然的趋势,DB2 V9 中就提供了对 XML 的强大支持—— pureXML 。为更好地探讨 pureXML,让我们简单回顾一下 XML 的相关知识。

下面是一个简单的 XML 文档。

<?xml version="1.0" encoding="UTF-8"?> 
 <book> 
  <authors> 
  <author  id= “ 47 ” > 张 三 </author> 
  <author  id= “ 58 ” > 李 四 </author> 
  </authors> 
  <title> 数据库系统 </title> 
  <price>99</price> 
  <keywords> 
  <keyword>SQL</keyword> 
  <keyword> 关系 </keyword> 
  </keywords> 
 </book>

可以看到,XML 非常直观,由一系列的开始、结束标签,元素和相应的数据组成,如图 4.1 所示。

 图书信息 书名:DB2 V9/9.5 高级应用开发
作者:管松 主编,肖振春 张建伟 林光国 王东明 等编著
出版日期:2009 年 1 月
ISBN:978-7-121-07421-9
购买: 中国互动出版网当当网卓越网

推荐章节:

更多推荐书籍,请访问 developerWorks 图书频道

欢迎您对本书提出宝贵的反馈意见。您可以通过本页面最下方的 建议 栏目为本文打分,并反馈您的建议和意见。

如果您对 developerWorks 图书频道有什么好的建议,欢迎您将建议发给我们


图 4.1 XML 介绍
图4.1  XML介绍

XML 本身的特点决定了它非常适合于数据的交换,集成,演化和 Web 服务。 XML 与其相关的衍生技术推动了 Web 应用、Web 服务和 SOA 等的巨大发展。

2 . XML Schema(XML 模式)

我们可以利用 XML Schema 来描述和约束 XML 文档,Schema 文档本身也是 XML 格式,功能比早期的 DTD 模式定义语言强大。

XML Schema 文档中定义了可出现的元素、元素的属性、子元素、顺序、数量和数据类型等,例如利用 Microsoft VisualStudio,我们可以构建上述 XML 文档的对应的 Schema,如图 4.2 所示。


图 4.2 XML Schema
图4.2  XML Schema

3 . DOM 对比 SAX

XML 文档通过解析后可以从中提取有价值的信息,很多工具包可以实现 XML 文档的解析,从实现的机理上看,主要有两种方式:DOM 和 SAX 。

DOM 方式将整个 XML 文档加载到内存中,并解析成树形结构,如图 4.3 所示,开发人员可以遍历这个树形层次结构,获取信息。


图 4.3 XML DOM 树
图4.3  XML DOM树

DOM 解析方式简单快速,但由于要求将整个 XML 文档加载到内存中,对于大文档,DOM 不如 SAX 有优势,SAX 采用事件驱动的方式,以流的方式处理 XML 文档中的标签,可以不必解析整个文档,在适宜的时候退出处理即可,如图 4.4 所示。


图 4.4 XML SAX 解析
图4.4  XML SAX解析

4 . XPath、XSLT 和 XQuery

XPath 语言可以用来访问 XML 文档中的部分信息,是 XSLT 和 XQuery 的基础。 XPath 可以确定文档中的一组节点(0 个或多个),如 /book/authors/author 可以得到张三、李四两个节点。

XPath 比文件系统的路径表达更复杂、更强大,通过使用不同的轴,XPath 可以方便地指定某个节点的属性、子节点、父节点、后代及祖先等。同时通过使用谓词技术,XPath 可以轻松地实现根据特定条件选定节点集合。

/book/authors/author[@id = ‘ 58 ’ ] 可以得到李四。

XSLT 是一种根据既定的规则将 XML 从一种格式转换为另外一种格式的方法,如图 4.5 所示。


图 4.5 XSLT
图4.5  XSLT

XQuery 则是为查询 XML 数据而设计的语言,由一系列的数据模型,XPath 路径语言,表达式,相关的支持函数和操作符等组成。 W3C 的 XQuery 行业标准,采用 FLWOR 形式的表达式。下面是 DB2 中的一个 XQuery 例子。

For  $d in db2-fn:xmlcolumn( ‘ booktable.bookinfo ’ )/book 
 Let $aut := $d//authors/author 
 Where $d/price 
 
 Order by $d//authors/author/@ID 
 Return  <AuthorList>  
   {$aut} 
   </AuthorList >

DB2 V9 中实现了对 XQuery 的直接支持,可以高效地处理 XQuery 的分析、评估、优化和执行,从而使得 DB2 成为同时原生支持 SQL 与 XQuery 的混合引擎。后续的章节中将对此详细介绍。

4.1.2 XML 数据库

XML 语言由于本身的自描述,易于扩展的层次结构等优良特性,在数据库领域也得到了广泛的应用,出现了许多原生的 XML 数据库(Native XML Database),XML 使能关系数据库 (XML Enabled Database),以及将 XML 与关系融合的数据库—— DB2 V9 。

1 .原生 XML 数据库

专门用来设计存储 XML 文件的数据库,与关系数据库产品一样,这些原生的 XML 数据库产品也支持安全、并发访问、查询、增删改、事务管理及提供合适的编程接口等,但区别于关系数据库的关系模型,原生的 XML 数据库内部数据模型是 XML 。

XML 数据模型给 XML 原生数据库带来的巨大的灵活性,同时也给数据规范化,引用完整性,索引的复杂性等带来了许多挑战。

2 . XML 使能关系数据库

由于历史的原因,关系型数据库处于数据库产业的统治地位,海量的数据以关系表的方式存储在各种关系型数据库中。随着 XML 发展为因特网上标准的数据传输格式,XML 使能关系数据库也应运而生,严格意义上讲,XML 使能关系数据库基于原有的关系型数据库,将关系型数据以 XML 格式发布出去(Publishing),以及将 XML 数据拆解成关系表(Shredding)的技术实现,如图 4.6 所示。


图 4.6 拆解和发布
图4.6  拆解和发布

3 .关系与 XML 融合的 DB2 V9

DB2 V9 通过引入 pureXML 技术,提供了对 XML 数据的原生存储、索引、Schema 校验、XQuery 查询以及更新等支持,从而将原生 XML 数据库的优势与成熟的关系数据系统有机地融合在一起。

在 DB2 V9 里面,XML 与 SQL 的融合渗透到每一个层面,对用户而言,SQL 和 XML 开发人员都能从中看到这种融合带来的强大潜能,如图 4.7 所示。


图 4.7 DB2 V9 pureXML
图4.7  DB2 V9 pureXML

现在用户可以采用将 XQuery 嵌入 SQL,或者将 SQL 嵌入 XQuery 的集成的方式访问存储在 DB2 中的关系表和 XML 中的数据,如图 4.8 所示。


图 4.8 DB2 混合引擎
图4.8  DB2混合引擎

在接下来的章节中,作者将详细介绍这种融合带来的灵活性和强大的访问能力。





回页首


4.2 DB2 V9 中的 pureXML

4.2.1 pureXML 特性

DB2 V9 中的 pureXML 实现了对 XML 数据的原生支持,具有以下几个特点。

符合行业标准:XML、XQuery 和 Schema 等,IBM 积极参与 XML 与数据库相关的标准研究,努力促进标准的演化;

充分的灵活性:XML 本身具有很高的灵活性,并随应用不断演化;

高效:原生的层次化(类似 DOM)存储 XML 数据加上精炼的索引实现,提高了查询与访问的效率;

继承原 DB2 可靠性和可扩展性等特性,和 API 良好集成,关系型与层次化的充分融合。

1 .原生存储

DB2 V9 实现了对 XML 数据的原生存储,原生的含意是 XML 数据或文档,以一种符合 XML 数据模型的层次化树形结构存储在磁盘上,类似 DOM 的格式。这样避免了 XML 使能关系数据库中,把 XML 数据解析成关系表的复杂过程。

DB2 V9 中引入了一种新的 XML 数据类型,用来存储格式良好的 XML 文档,例如,我们可以建如图 4.9 所示的 books 表,bookInfo 列被设置成 XML 类型来记录该书籍的相关信息。

create table books (bookID CHAR(6), … , bookInfo XML);

逻辑上,XML 文档和表中的一条记录关联,但在物理上,XML 与关系数据的存储是不同的。它们以符合各自数据模型特点的格式存储,甚至存储在不同的表空间里面。

XML Schema 对于 XML 列而言不是必需的,Schema 是可选的,并且针对单一文档而不是整个列,提供了最大的灵活性。

XML 类型提供了直接的局部文档访问的能力,而不再需要每次解析整个 XML 文档。这种类似 DOM 的树形结构同时也易于实现简单的索引。

图 4.10 用来表示树形的 XML 是如何分页存储在 DB2 的表空间上的。

图 4.9 books 表的物理存储 图 4.10 XML 存储组织

XML 的节点层次是以节点树的方式存放在 DB2 数据页上的,若节点树大于单页容量,就被拆分成多个域,同一个页上的节点物理地相互连接,而不同域上的节点通过域索引逻辑地连接在一起。这种设计更多地考虑到对节点树的向上和向下的遍历处理效率(XPath 中最核心的遍历操作),从而使得查询的效率得以提高。

XML 数据在插入的时候被解析一次,接着以上述的节点树方式存储,查询时直接读取节点树,而不需要再次解析,这是与 CLOB/BLOB 方式存储的本质区别。

目前,不管文档的编码设置,操作系统的 Locale,以及数据库的 Codepage 如何,DB2 对所有的 XML 数据以统一的 UTF-8 编码格式处理。

2 .索引

XML 索引与关系数据索引有显著的不同。 DB2 中的 XML 索引是基于 XMLPATTERN 表达式的,XMLPATTERN 表达式是 XPath 的子集,去除了谓词等的支持。通过指定 XMLPATTERN,用户可以建立对特定的 XML 元素和属性的索引。

需要注意的是,在建立索引时,除了要指定相应的 XMLPATTERN 路径外,还要注意指定将要在查询中用的类型。如果某个节点符合指定的路径,而类型不匹配,将会报错。

文档中可能有 0 到多个节点符合建立索引的条件,DB2 会相应地建立 0 到多个索引,这一点与关系数据的索引有显著的不同。

CREATE INDEX idx1 ON books(bookInfo) GENERATE KEY USING 
 XMLPATTERN '/book/authors/author' AS SQL VARCHAR(35);

上面的语句定义了针对 books 表中 bookInfo 列存储的所有 XML 文档中的 /book/authors/ author 的索引。这里的 /book/authors/author 就是 XMLPATTERN 语句。

3 .新的拆解方式

XML 的拆解方式,就是上文中提到的 Shredding,也就是将 XML 文档拆分成关系数据中的一张或多张表。有必要在这里提一下 IBM 使能数据库产品中拆解的两个经典的实现:DB2 XML Extender 和 DB2 Information Integrator(现在称为 Websphere Federation Server)中的 XML Wrapper 。

XML Wrapper 在数据联邦的架构下如图 4.11 所示。


图 4.11 XML Wrapper 架构
图4.11  XML Wrapper架构

XML Wrapper 处在 DB2 引擎和 XML 数据源(XML 文档,链接甚至是 Web Service)之间,它的角色是与 DB2 引擎协同处理查询请求,解析 XML 文档,获取其中数据,动态地将这些数据拆解成关系数据表(Nickname)。

CREATE NICKNAME books 
   (title VARCHAR(32) OPTIONS(XPATH ‘ ./title/text() ’ ), 
   pk VARCHAR(16) OPTIONS(PRIMARY_KEY ‘ YES ’ ))  
   FOR SERVER xml_server  
   OPTIONS(FILE_PATH ‘ C:\book.xml ’, XPATH ‘ /book ’ )  
 CREATE NICKNAME authors 
   (id INTEGER OPTIONS(XPATH ‘ ./author/@id ’ ), 
   name VARCHAR(32) OPTIONS(XPATH ‘ ./author/text() ’ ), 
   fk VARCHAR(16) OPTIONS(FOREIGN_KEY ‘ books ’ )) 
   FOR SERVER xml_server 
   OPTIONS(XPATH ‘ ./authors ’ )

可以看到 XML Wrapper 通过在 DDL 以指定表的列对应的 XPath 的方式,定义对 XML 数据的拆解。

而 XML Extender 则是利用一种名为文档访问定义(Document Access Definition,DAD)的映射文件,用于将 XML 文档映射到关系数据表中,如图 4.12 所示。 DAD 文件是一个 XML 文档,其中的元素称为标签,而 XML 文档中的元素称为元素。


图 4.12 XML Extender
图4.12  XML Extender

由于 XML Extender 仅支持功能有限的 XML 文档分解 Schema,而且受到 DAD 的约束,DB2 V9 中用带注释的 XML Schema 分解取代了 XML Extender 的拆解方式,带注释的 XML Schema 分解更加灵活、更加快速。这种新的带注释的 XML Schema 分解特性可用于将 XML 文档整个或部分地分解成关系表。它基于 XML 的 Schema,以 XML Schema 中的注释作为映射语言,将 XML 文档中的信息映射为关系表。

关系数据具有更加快速的处理速度,存在大量的旧应用系统,从而使 XML 拆解仍然具有重要意义,它可以把数据适配提供给这些成熟的系统,而无须修改这些应用。

<xsd:element name= “ book" type="xsd:string “ 
  db2-xdb:rowSet="books" 
  db2-xdb:column= “ bookInfo"/>

将名为 book 的元素存放于 books 表的 bookInfo 列中。

4 . Schema 支持

DB2 V9 中 XML 支持的一个重要的特性就是 XSR(XML Schema Repository)。 XSR 被用于储存与 XML Schema 和校验相关的文档。上文中提到的 XML Schema 用来指定 XML 元素、数据类型和顺序等,针对 Schema 来验证相应的 XML 文档,是保证 XML 数据完整性的基础。

DB2 V9 中的 pureXML 基于 XSR 对 XML Schema 的存储,支持 Schema 注册,以及对实体文档的校验。将我们用 Microsoft Visual Studio 产生的简单不引用其他 Schema 的 books.xsd 注册到 DB2 中。

register xmlschema 'http://books.ibm.com' from 'C:/books.xsd' as qing.booksample complete;

books.xsd 注册到 qing.boosample 的存储库中,以 http://books.ibm.com 占位符来标识在 XML 的实例文档中引用的 URI,“ complete ”表示完成注册以便用于 Schema 校验。

XMLValidate 是唯一用于 XML 文档针对特定 Schema 校验的方式。

|--XMLVALIDATE--(---|xml-expression|-+-------------------------+--)---| 
   '--| XML-validate-according-to-clause |--' 
 XML-validate-according-to-clause 
 |--ACCORDING TO XMLSCHEMA--+--ID--registered-XML-schema-name---------------+--> 
   '--+--URI--xml-uri1---------+--+--------------------------+--' 
   '--NO NAMESPACE----'  '-LOCATION--xml-uri2--' 
 >--+------------------------------+--------------------------------| 
   '--| XML-valid-element-clause |--' 
 XML-valid-element-clause 
 |---+----------------------------+------ELEMENT----| XML-element-name-----| 
  '--NAMESPACE---| xml-uri3 |--'

XMLValidate 返回一个用 XML Schema 中定义的默认值和类型注释生成的 XML 值,如图 4.13 所示。


图 4.13 XML Validate
图4.13  XML Validate

DB2 V9 没有提供针对整个列的 XML Schema 验证,验证必须显式地添加到每个 insert 或 update 语句中。这是出于灵活性的考虑,允许把不同 XML Schema 的 XML 文档保存在同一列中。

insert into books (bookID,bookInfo) values (2356, XMLValidate(?))

用户在 SQL 语句 WHERE 子句中,用 is validated 谓词检查 XML 数据是否已经经过验证。

4.2.2 查询应用与编程

DB2 V9 拓展了 v8 中的 SQL/XML 功能,提供了以 SQL 为基础查询语言,嵌入 XQuery (SQL/XML)和以 XQuery 为基础查询语言,嵌入 SQL(XQuery)两种灵活的查询方式支持。

pureXML 处理过程如图 4.14 所示。


图 4.14 pureXML 处理
图4.14  pureXML处理

0 . pureXML 的融合 XML 与关系表的数据模型

1 .绑定 XML 到数据库引擎

2 . XML 文档存储

3 .将 XML 拆解成为关系表,SQL 查询

4 .获取 XML

5 . XML 发布

6 .将 XML 类型数据绑定出去

7 . XML 到 XML 的转换

8 . XML 到 SQL 关系表转换

9 . SQL 关系表到 XML 转换

下面以简单的 XML 文档为例,分别介绍这两种查询方式。

<doc> 
   <employee> 
   <empname>Smith</empname> 
   <salary>24000</salary> 
   <empno>20607</empno> 
  <commission>.2</commission> 
   </employee> 
   <employee> 
   <empname>Smith</empname> 
   <salary>12000</salary> 
   <empno>40203</empno> 
   <commission>.7</commission> 
   </employee> 
  <employee> 
   <empname>Jones</empname> 
   <salary>20000</salary> 
   <empno>492399</empno> 
   <commission>.5</commission> 
   </employee> 
 </doc>

1 . SQL/XML

v8 已有对下列 XML 发布函数的支持:

  • XMLAGG:连接非空的 XML 值;
  • XMLATTRIBUTES: 生成 XML 元素的属性;
  • XMLCONCAT: 连结非空的 XML 类型;
  • XMLELEMENT: 定义生成一个 XML 元素;
  • XMLFOREST:构建 XML 元素丛林;
  • XMLNAMESPACES:构造命名空间;
  • XML2CLOB 和 XMLSERIALIZE: 序列化 XML 到字符串。

v9 中增加的发布函数:

  • XMLCOMMENT:生成 XML 注释;
  • XMLPI:定义处理指令;
  • XMLTEXT:定义文本元素;
  • XMLDOCUMENT:生成 XML 文档。

用于输入输出和验证的函数:

  • XMLPARSE:解析 CLOB、BLOB ;
  • XMLCAST:类型转换;
  • XMLVALIDATE:Schema 验证;
  • IS VALIDATED: 检查是否已验证。

新的查询 XML 数据的函数和谓词:

  • XMLTABLE:将 XML 序列映射成关系表;
  • XMLEXISTS:检测是否存在返回结果;
  • XMLQUERY:执行 XQuery 得到结果序列。

假定数据库中已有如下的一张表:

FISTNAME             LASTNAME             DEPT 
 ------------- ------------ -------------- 
 sean                 lee                  A00 
 michael              johnson              B01 
 christine            smith                A00

下面是综合利用上述函数的例子,及相应的注解。

例子,及相应的注解

另外在数据库中构造这样一张表:

CID  INFO 
 ----------------------------------------------------------------- 
  1000 <doc> 
	  <employee> 
		  <empname>Smith</empname> 
		  <salary>24000</salary> 
		  <empno>20607</empno> 
		  <commission>0.2</commission> 
	  </employee> 
	  
	  <employee> 
		  <empname>Smith</empname> 
		  <salary>12000</salary> 
		  <empno>40203</empno> 
		  <commission>0.7</commission> 
	  </employee> 
	  
	  <employee> 
		  <empname>Jones</empname> 
		  <salary>20000</salary> 
		  <empno>49239</empno> 
		  <commission>0.5</commission> 
	  </employee> 
       </doc> 
 1001 <doc> 
		 <employee> 
			 <empname>wang</empname> 
			 <salary>24000</salary> 
			 <empno>20607</empno> 
			 <commission>0.2</commission> 
		 </employee> 
		
		 <employee> 
			 <empname>qqq</empname> 
			 <salary>12000</salary> 
			 <empno>40203</empno> 
			 <commission>0.7</commission> 
		 </employee> 
		
		 <employee> 
			 <empname>fafa</empname> 
			 <salary>20000</salary> 
			 <empno>49239</empno> 
			 <commission>0.5</commission> 
		 </employee> 
		 </doc> 
 1002 <doc> 
		 <employee> 
			 <empname>cdl</empname> 
			 <salary>24000</salary> 
			 <empno>20607</empno> 
			 <commission>0.2</commission> 
		 </employee> 
		
		 <employee> 
			 <empname>mysel</empname> 
			 <salary>12000</salary> 
			 <empno>40203</empno> 
			 <commission>0.7</commission> 
		 </employee> 
		
		 <employee> 
			 <empname>temo</empname> 
			 <salary>20000</salary> 
			 <empno>49239</empno> 
			 <commission>0.5</commission> 
		 </employee> 
		 </doc>

使用 XMLQuery 在 SQL 中嵌入 XQuery 查询。

在SQL中嵌入XQuery查询

注意 XQuery 与 SQL 中传递 XML 类型数据的方式。

passing <xml 列名 > as <xml 文档占位符 >

下面是一个使用 XMLTABLE 拆解 XML 数据为关系表的例子。

select X.*  from xmlcustomer, \ 
 xmltable ( \ 
  '$d/doc/employee' passing info as "d" \ 
  columns \ 
  "name" varchar(20) path 'empname', \ 
  "earnings" integer path 'salary', \ 
  "number"  integer  path 'empno' \ 
 ) as "X" 
 name earnings  number 
 ------ ----- ----- 
 Smith 24000  20607 
 Smith 12000  40203 
 Jones 20000  49239

2 . XQuery

让我们先了解一下 DB2 V9 中的 XDM(XQuery Data Model),仍然以 book.xml 为例,在 DB2 中,采用如图 4.15 中的节点序列的方式组织。


图 4.15 XDM
图4.15  XDM

共有 6 种不同的 XML 节点:

  • 文档节点;
  • 元素节点;
  • 属性节点;
  • 文本节点;
  • 注释节点;
  • 处理指令节点。

每种节点都有对应类型的节点值。

XQuery 的 FLWOR 查询语言可以在这样的节点序列中,依照 XPath 表达式指定的规则进行遍历,获取相应的查询结果。

用以下语句建表。

CREATE TABLE xmltable ( num INTEGER,xdata XML ) 
 INSERT INTO xmltable VALUES \ 

  (1,XMLPARSE(DOCUMENT'<doc> <type>car</type> 
  <make>Pontiac</make> 
  <model>Sunfire</model> 
  </doc>'PRESERVE WHITESPACE)), \ 
  (2,XMLPARSE(DOCUMENT'<doc> <type>car</type> 
  <make>Mazda</make> <model>Miata</model> 
   </doc>'PRESERVE WHITESPACE)), \ 
  (3,XMLPARSE(DOCUMENT'<doc> <type>person</type> 
  <name>Mary</name> <town>Vancouver</town> 
  <street>Waterside</street> </doc>'PRESERVE WHITESPACE)), \ 
  (4,XMLPARSE(DOCUMENT'<doc> <type>person</type> 
  <name>Mark</name> <town>Edmonton</town> 
  <street>Oak</street> </doc>'PRESERVE WHITESPACE)), \ 
  (5,XMLPARSE(DOCUMENT'<doc> <type>animal</type> 
  <name>dog</name> </doc>'PRESERVE WHITESPACE)), \ 
  (6,NULL),  \ 
  (7,XMLPARSE(DOCUMENT'<doc> <type>car</type> 
   <make>Ford</make> <model>Taurus</model> 
   </doc>'PRESERVE WHITESPACE)), \ 
  (8,XMLPARSE(DOCUMENT'<doc> <type>person</type> 
  <name>Kim</name> <town>Toronto</town> 
  <street>Elm</street> </doc>'PRESERVE WHITESPACE)), \ 
  (9,XMLPARSE(DOCUMENT'<doc> <type>person</type> 
  <name>Bob</name> <town>Toronto</town> 
  <street>Oak</street> </doc>'PRESERVE WHITESPACE)), \ 
  (10,XMLPARSE(DOCUMENT'<doc> <type>animal</type> 
  <name>bird</name> </doc>'PRESERVE WHITESPACE))

试验下面的 XQuery,篇幅的原因不在此罗列查询结果,建议读者自己实践。

xquery for $d in db2-fn:xmlcolumn('XMLTABLE.XDATA')/doc \ 
 where $d/type = "car" \ 
 return <CarName> \ 
 {$d/name } \ 
 </CarName> 

 xquery for $d in db2-fn:sqlquery('select XDATA from XMLTABLE where NUM = 3')/doc \ 
 where $d/type = "car" \ 
 return ( <CarName> \ 
 {$d/name } \ 
 </CarName> )

db2-fn:sqlquery 返回 SQL 查询到的 XML 元素集合;

db2-fn:xmlcolumn 返回整个 XML 列。

3 .工具集与编程开发支援

pureXML 在 DB2 相应的工具集和应用程序 API 中也得到了支持。用户可以使用下面的各种语言开发应用,存取 DB2 表中的 XML 数据,或者以 XML 参数调用用户自定义函数,以及存储过程。

各种开发语言:

  • C or C++ (embedded SQL or DB2 CLI) ;
  • COBOL ;
  • Java™ (JDBC or SQLJ) ;
  • C# and Visual Basic (DB2 .NET Data Provider) ;
  • PHP 。

通用的数据库访问接口 ODBC/JDBC 也同样得到了增强,甚至服务于流行应用框架的数据驱动层也实现了 XML 扩展,例如用于 Ruby On Rails 的 IBM DB2 Driver 。

在集成开发环境中,比如 DB2 Developer Workbench(见图 4.16)和 Microsoft Visual Studio .Net 中的 DB2 开发插件,用户可以直观地操作 XML 数据,并很容易的将这些操作集成到自己的应用程序中。


图 4.16 DB2 Developer Workbench
图4.16  DB2 Developer Workbench

图 4.17 DB2 Visual Studio 插件
图4.17  DB2 Visual Studio插件




回页首


4.3 pureXML 应用开发实例

4.3.1 存储过程

我们以一个存储过程中使用前面讲到的两种查询方式为例,做一次简单的实战演练。通常开发一个 C 语言的存储过程包括以下三步。

用 CREATE PROCEDURE 语句定义存储过程原型,类似 C 语言中头文件中的方法定义;

在 C 源代码中实现需要的逻辑,必要的地方嵌入 SQL ;

绑定编译连接与部署。

我们看《 Developing SQL and External Routines 》中的一个例子。

Chapter 5. External routines 
  C and C++ routines 
  Examples of C and C++ routines 
  Example: XML and XQuery support in C procedure

作者对该例子进行了简化,修改了其中的一些问题。

存储过程定义如下。

create procedure xmlProc1 ( IN inNUM integer, \ 
 IN inXML xml as clob (1k), \ 
 out out1XML xml as clob(1k), \ 
 out out2XML xml as clob(1k)) \ 
 language c \ 
 parameter style sql \ 
 dynamic result sets 0 \ 
 fenced \ 
 threadsafe \ 
 deterministic \ 
 no dbinfo \ 
 modifies sql data \ 
 program type sub \ 
 external name 'gwenProc!xmlProc1'

以上文中建立的表 xmltable 为访问的数据对象,存储过程的源代码如下。

// stored procedure: xmlProc1 
 #include <stdio.h> 
 #include <string.h> 
 #include <stdlib.h> 
 #include <sqlda.h> 
 #include <sqlca.h> 
 #include <sqludf.h> 
 #include <sql.h> 
 #include <memory.h> 
 #ifdef __cplusplus 
 extern "C" 
 #endif 
 SQL_API_RC SQL_API_FN xmlProc1 ( sqlint32* inNum, 
  SQLUDF_CLOB* inXML, 
  SQLUDF_CLOB* out1XML, 
  SQLUDF_CLOB* out2XML, 
 SQLUDF_NULLIND *inNum_ind, 
  SQLUDF_NULLIND *inXML_ind, 
  SQLUDF_NULLIND *out1XML_ind, 
  SQLUDF_NULLIND *out2XML_ind, 
 SQLUDF_TRAIL_ARGS) 
 { 
 EXEC SQL INCLUDE SQLCA; 
 EXEC SQL BEGIN DECLARE SECTION; 
  char stmt1[1000], stmt2[1000]; 
  sqlint32 hvNum; 
  SQL TYPE IS XML AS CLOB(2000) hvXML, hvXML1, hvXML2; 
 EXEC SQL END DECLARE SECTION; 

 if ((*inNum_ind < 0) || (*inXML_ind <0)) 
 { 
  strcpy(sqludf_sqlstate, "38100"); 
  strcpy(sqludf_msgtext, "received null input"); 
  return 0; 
 } 
 hvNum = *inNum; 
 hvXML.length = inXML->length; 
 strncpy(hvXML.data, inXML->data, inXML->length); 
 //Insert Data 
 EXEC SQL INSERT INTO xmltable (num, xdata) VALUES (:hvNum, :hvXML); 
 //XQuery with SQL embedded in it 
 sprintf(stmt1, " select xmlquery('for $i in $d/doc let $j := $i/name return $j'
  passing xdata as \"d\") from xmltable  
  where xmlexists ('$d/doc/type = \"car\"' passing xdata as \"d\") "); 
  
 EXEC SQL PREPARE s1 FROM :stmt1; 
 EXEC SQL DECLARE c1 CURSOR FOR s1; 
 EXEC SQL OPEN c1 ; 
 while( sqlca.sqlcode == SQL_RC_OK ) 
 { 
  EXEC SQL FETCH c1 INTO :hvXML1; 
 } 
 EXEC SQL CLOSE c1; 
 out1XML->length = hvXML1.length; 
 strncpy(out1XML->data, hvXML1.data, hvXML1.length); 
 *out1XML_ind = 0; 
 //SQL with XQuery embedded in it 
 sprintf(stmt2, " xquery for $d in db2-fn:sqlquery('select XDATA from XMLTABLE ')/doc 
 where $d/type = \"car\" return ( <CarName> {$d/name }  </CarName> ) "); 
 
 EXEC SQL PREPARE s2 FROM :stmt2; 
 EXEC SQL DECLARE c2 CURSOR FOR s2; 
 EXEC SQL OPEN c2; 
 while( sqlca.sqlcode == SQL_RC_OK ) 
 { 
  EXEC SQL FETCH c2 INTO :hvXML2; 
 } 
 EXEC SQL CLOSE c2; 
 out2XML->length = hvXML2.length; 
 strncpy(out2XML->data, hvXML2.data, hvXML2.length); 
 *out2XML_ind = 0; 
 EXEC SQL COMMIT; 
 exit: 
  return sqlca.sqlcode; 
  }

绑定、编译、连接及部署以后(存储过程请参考本书相关章节),调用如下。

CALL xmlproc1 (2, XMLPARSE(DOCUMENT '<doc> 
 <type>fruit</type> 
 <name>apple</name> 
 </doc>' PRESERVE WHITESPACE),?,?)

得到如下类似地结果。

------------------ 
 OUT1XML 
 <name>apple</name> 
 OUT2XML 
 <CarName/>

4.3.2 Ruby On Rails 集成

Ruby On Rails 是目前比较流行的开源 Web 框架,简单易用,震撼了整个 Web 开发领域。读者可以在 http://www.ibm.com/developerworks/cn/linux/l-rubyrails/ 找到 David Mertz 博士深入浅出的介绍。

本示例试着带读者建立一个在 RoR 中使用 pureXML 的原型应用,在体验 RoR 为创建 Web 应用带来的神奇便利之中,领会将 pureXML 与 RoR 整合的无限应用潜力。

1 .示例应用的环境搭建

假定读者采用与作者相同的 Ubuntu Linux 系统。

(1)安装 Ruby, RubyGems

用下面的命令安装 RoR 。

gem install rails --include-dependencies

(2)安装 DB2 V9

(3)下载并安装用于 RoR 的 DB2 适配驱动

下载地址 http://www.alphaworks.ibm.com/tech/db2onrails 。如果读者期望在 Windows 上使用,可以全部 Starter Toolkit,按照包中的说明进行编译安装。

rake 
 cp ibm_db2_adapter.rb  
	 /var/lib/gems/1.8/gems/activerecord-1.15.3/lib/active_record/connection_adapters 
 cp ibm_db2.so /usr/local/lib/site_ruby/1.8/i486-linux

(4)创建数据库

CREATE DATABASE devdb AUTOMATIC STORAGE YES  ON '/home/qing' 
 USING CODESET UTF-8 TERRITORY GB COLLATE USING SYSTEM PAGESIZE 4096; 
 CREATE DATABASE testdb AUTOMATIC STORAGE YES  ON '/home/qing' 
 USING CODESET UTF-8 TERRITORY GB COLLATE USING SYSTEM PAGESIZE 4096; 
 CREATE DATABASE prodb AUTOMATIC STORAGE YES  ON '/home/qing' 
 USING CODESET UTF-8 TERRITORY GB COLLATE USING SYSTEM PAGESIZE 4096;

准备就绪之后,开始生成 Web 应用框架。

2 .生成 Web 应用原型框架

(1)生成名为 bookstore 的 RoR 应用

rails bookstore

(2)emacs bookstoree/config.database.yml 改为下面内容,提供数据库配置信息给 RoR

development: 
  adapter: ibm_db2 
  database: devdb 
  username: qing 
  password: ******* 
  host: localhost 
 # Warning: The database defined as 'test' will be erased and 
 # re-generated from your development database when you run 'rake'. 
 # Do not set this db to the same as development or production. 
 test: 
  adapter: ibm_db2 
  database: testdb 
  username: qing 
  password: ******* 
  host: localhost 
 production: 
  adapter: ibm_db2 
  database: prodb 
  username: qing 
  password: ******* 
  host: localhost

(3)运行脚手架生成所需要的 REST 风格的代码框架,REST 是被逐渐看好的简单的 Web 应用程序架构方式,因篇幅原因,在此不做详细探讨。

qing@ubuntu:~/bookstore$ ruby script/generate scaffold_resource book bookid:string 
  exists  app/models/ 
  exists  app/controllers/ 
  exists  app/helpers/ 
  create  app/views/books 
  exists  test/functional/ 
  exists  test/unit/ 
  create  app/views/books/index.rhtml 
  create  app/views/books/show.rhtml 
  create  app/views/books/new.rhtml 
  create  app/views/books/edit.rhtml 
  create  app/views/layouts/books.rhtml 
  create  public/stylesheets/scaffold.css 
  create  app/models/book.rb 
  create  app/controllers/books_controller.rb 
  create  test/functional/books_controller_test.rb 
  create  app/helpers/books_helper.rb 
  create  test/unit/book_test.rb 
  create  test/fixtures/books.yml 
  create  db/migrate 
  create  db/migrate/001_create_books.rb 
  route  map.resources :books

(4)脚手架生成器生成数据库迁移方案如下例所示,RoR 用记录迁移方案的方法处理应用数据库设计方案,并进行版本控制。

qing@ubuntu:~/bookstore$ more db/migrate/001_create_books.rb 
 class CreateBooks < ActiveRecord::Migration 
  def self.up 
  create_table :books do |t| 
  t.column :bookid, :string 
  end 
  end 
  def self.down 
  drop_table :books 
  end 
 end

(5)应用数据库迁移。

qing@ubuntu:~/bookstore$rake db:migrate(in /home/qing/bookstore) 
 == CreateBooks: migrating =================== 
 -- create_table(:books) 
  -> 0.0485s 
 == CreateBooks: migrated (0.0489s) ==================

到此我们的 Web 应用框架已经搭建好,下一步将 pureXML 集成进来。

3 . pureXML 的集成

(1)首先定义数据库迁移,增加 XML 数据列。

qing@ubuntu:~/bookstore$ ruby script/generate migration add_xml_doc_column 
  exists  db/migrate 
  create  db/migrate/002_add_xml_doc_column.rb 
 qing@ubuntu:~/bookstore$ more db/migrate/002_add_xml_doc_column.rb 
 class AddXmlDocColumn < ActiveRecord::Migration 
  def self.up 
  end 
  def self.down 
  end 
 end

(2)修改新生成的迁移文件,增加类型为 xml 的列 bookinfo 。

class AddXmlDocColumn < ActiveRecord::Migration 
  def self.up 
  add_column :BOOKS, :bookinfo, :xml 
  end 
  def self.down 
  end 
 end

(3)应用 rake db:migrate 后,看到:

qing@ubuntu:~/bookstore$ db2 "describe table books" 
 Column Type  Type 
 name schema name Length  Scale Nulls 
 ------- ----- ------ -------- ----- ------ 
 ID SYSIBM INTEGER 4  0 No 
 BOOKID SYSIBM VARCHAR 255  0 Yes 
 BOOKINFO SYSIBM XML 0  0 Yes

这里 ID 是 RoR 自动生成的列,也被用来作为 REST 中资源的描述,BOOKID 是第一次应用数据迁移加入的列,而 BOOKINFO 则是此次应用迁移的 XML 列。我们的应用已经完成了,下面来看看效果如何。

4 .应用与完善

(1)启动 Web 服务器。

ruby script/server webrick

(2)在浏览器中输入地址 http://yourip:3000/books,得到如图 4.18 所示的界面。


图 4.18 获取 books
图4.18  获取books

单击 New book 超链接,发现没有针对 XML 的文本框,需要对代码稍加修改。

(3)新视图代码如图 4.19 所示,显示代码及编辑代码分别如图 4.20 和图 4.21 所示。

~/bookstore/app/views/books/new.rhtml 
 ~/bookstore/app/views/books/show.rhtml 
 ~/bookstore/app/views/books/edit.rhtml

图4.19和图4.20

(4)保存,刷新浏览器,单击 New book 超链接,得到如图 4.22 所示的界面,输入一条记录— 123456 。

图4.21和图4.22

单击“ Create ”按钮后看到如图 4.23 所示的显示记录。

Show 一下我们刚才输入进入数据库的内容,如图 4.24 所示。

图4.23和图4.24

Edit 这条记录,比如去掉命名空间的限制,然后提交。读者可能注意到地址栏中的 http://<yourip>:3000/books/100,这就是我们刚创建的数据记录在 REST 中的资源 ID,100 是 RoR 为我们自动生成的。我们同样可以用 curl 工具看到其中的内容。

qing@ubuntu:~/bookstore$ curl -H "Accept: application/xml" 
			-i -X GET http://localhost:3000/books/100 
			
 HTTP/1.1 200 OK 
 Cache-Control: no-cache 
 Connection: Keep-Alive 
 Date: Thu, 21 Jun 2007 06:05:23 GMT 
 Content-Type: application/xml; charset=utf-8 
 Server: WEBrick/1.3.1 (Ruby/1.8.5/2006-08-25) 
 Content-Length: 601 
 Set-Cookie: _bookstore_session_id=afdffcf5f66096ad5b4e0de34cf78fa9; path=/ 
 <?xml version="1.0" encoding="UTF-8"?> 
 <book> 
  <bookid>123456</bookid> 
  <bookinfo type="xml"><?xml version="1.0" encoding="UTF-8" ?> 
  <book> 
  <authors> 
  <author id="47"> 张 三 </author> 
  <author id="58"> 李 四 </author> 
  </authors> 
  <title> 数据库系统 </title> 
  <price>29</price> 
  <keywords> 
  <keyword>SQL</keyword> 
  <keyword> 关系 </keyword> 
  </keywords> 
  </book> 
  </bookinfo> 
  <id type="integer">100</id> 
 </book>

(5)用 find_by_sql 直接使用 XQuery

在 ~/bookstore/app/controllers/books_controller.rb 的 show 动作模块中加入 find_by_sql 获取含有关键字 SQL 的 book 的 title,如图 4.25 所示。


图 4.25 获取 book title 的代码
图4.25  获取book title的代码

修改 ~/bookstore/app/views/books/show.rhtml 为如图 4.26 所示代码。


图 4.26 show 代码
图4.26  show代码

保存,刷新浏览器,得到如图 4.27 所示结果。


图 4.27 获取 book title 的结果
图4.27  获取book title的结果

很显然 title 不是我们想要的样子,多了个 <?xml version="1.0" encoding="UTF-8" ?>,如何调整我们的应用或者 RoR,去掉这个 XML 头呢,读者可以此为切入点去深入研究 pureXML 与 RoR 的集成。请参考较为深入的探讨 http://www.ibm.com/developerworks/ db2/library/techarticle/dm-0705chun/ 。





回页首


4.4 本章小结

PureXML 技术的引入,为 DB2 提供了原生存储、索引、Schema 校验和 XML 数据查询的原生支持,并且与成熟的关系数据系统有机地融合,带来了数据库层面的非常灵活与强大的应用潜能。

关系数据库在结构化数据处理领域中有着不可替代的作用,而 pureXML 则在数据复杂多样,格式不断变化,实例数据稀疏分布等半结构化数据处理领域中具有先天的优势。以医疗行业为例,pureXML 的应用可以轻松地处理复杂数据:从管理到临床产生的表格、文本、影像、X 光、B 超、CT、细胞学 / 病理学影像及动态视频等。 DB2 V9 的 pureXML 技术被认为是医疗行业信息化加速的希望。

XML 作为数据交换的标准已经逐步为更多的行业采用,因而 XML 数据的持久化存储,信息检索,集成,数据的分析挖掘等的旺盛需求也逐步推动了数据库市场的技术变革。我们可以预见,融合传统的关系型数据库和先进的 pureXML 支持的数据库技术将在数据库市场上扮演着承前启后的作用。



读者反馈

欢迎您对本书提出宝贵的反馈意见。您可以通过本页面最下方的 建议 栏目为本文打分,并反馈您的建议和意见。

如果您对 developerWorks 图书频道有什么好的建议,欢迎您将建议发给我们



参考资料

学习

获得产品和技术
  • 现在可以免费使用 DB2 。下载 DB2 Express-C,这是为社区提供的 DB2 Express Edition 的免费版本,它提供了与 DB2 Express Edition 相同的核心数据特性,为构建和部署应用程序奠定了坚实的基础。

  • 下载 信息管理软件试用版,体验它们强大的功能。


讨论


作者简介

管松,现为IBM中国软件开发中心企业内容管理产品(Content Manager)开发经理,毕业于中国科学院软件所,加入IBM研发中心工作后涉及领域包括Websphere Commerce,主机上的DB2数据库系统等。


肖振春,IBM中国软件开发中心高级工程师,毕业于北京航空航天大学。从事数据库领域信息整合和数据复制方面的工作,熟悉DB2应用开发和性能调优。


张建伟,IBM中国软件开发中心高级工程师,毕业于北京大学,从事主机上DB2研发工作。熟悉DB2内部实现,精通DB2 JDBC/SQLJ驱动程序。


林光国,IBM中国软件开发中心高级工程师,毕业于清华大学。曾作为IBM开发中心的首批DB2/i工程师在iSeries (AS400)平台上从事开发工作。目前任职于IBM Linux解决方案中心,从事企业应用方案的售前技术支持。


王东明,IBM中国软件开发中心高级工程师,毕业于南开大学,负责数据库领域IBM企业内容管理产品的开发和技术支持。个人技术兴趣主要在数据库系统和应用开发,Web应用开发领域。


闫庆宏,IBM中国软件开发中心工程师,毕业于东北大学。从事DB2主机研发相关的工作,参与PHP实际项目的开发。


李尚强,IBM中国软件开发中心高级工程师,毕业于清华大学。从事数据库领域内容管理方面的工作,熟悉DB2应用开发和性能调优。


王庆法,IBM中国软件开发中心高级工程师,毕业于清华大学,拥有10年以上软件开发经验。从事数据库领域信息整合方面的工作,熟悉DB2内部实现、XML及信息整合的架构。




对本文的评价








IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款