级别: 初级
陈 力
(chenli44@yeah.net), 北京师范大学信息管理专业研究生 张 大为 (zhangdaw@cn.ibm.com), 软件工程师
2006 年 9 月 21 日
摘要:本文将介绍 DB2 提供的一些基本 XML 函数,并结合一个简单的实例,重点介绍如何利用 DB2 提供的 XML 函数以视图或查询的形式灵活的实现 XML 文档的构造和发布。
DB2 提供了丰富的功能用以发布 XML 格式的数据,这种功能包括了 DB2 内置的 XML 函数以及 XML extender 提供的功能(包括了发布、解析、检索、存储等多种功能)。对 XML 文档的支持,使得利用现有的 DB2 数据库,就能够方便的实现系统或者数据的整合。
本文读者定位为具有一定的 DB2 开发经验,同时对 XML 语言的格式、schema 定义、命名空间等有基本的理解。
本文将介绍 DB2 提供的一些基本 XML 函数,并结合一个简单的实例,重点介绍如何利用 DB2 提供的 XML 函数以视图或查询的形式灵活的实现 XML 文档的构造和发布。同时文中还将介绍利用作者编制的一个工具,根据目标 XML 的样例文档生成相应的包含 XML 函数的查询框架,以辅助开发较为复杂的 XML 文档结构的 SQL 语句。
以 DB2 的 XML 函数为基础的 SQL 语句支持 XML 语言的绝大部分特征,可以简单而直观地实现从关系型数据模型到 XML 的树状结构的转换,其灵活性接近于手工书写 XML 文档,同时,只要利用适当的方法和工具,就可以在不增加开发复杂度的基础上大大降低开发的工作量。
1.DB2 XML 查询/视图及 XML 函数简介
利用 XML 函数我们可以方便的构建 XML 查询或视图,利用这些函数发布 XML 的整个过程与开发和使用传统的查询与视图并没有本质的区别。XML 查询不需要依赖于复杂的发布程序和软件平台,即使只有 DB2 命令行客户端,我们也能够连接数据库发布 XML 文档。可见利用这种方式进行 XML 发布具有很广泛的应用范围,能够适应从高级语言开发的网络程序到简单的 Shell 脚本这样不同级别实现的要求,而且特别有利于简单直接的解决方案。这给我们以 DB2 数据库为基础实现异构数据系统的整合与互动功能提供了一个简便易行的方法。
DB2 UDB 8.2 直接提供了 7 种 SQL/XML 函数,以及与这些 XML 语法成分对应的 XML 数据类型。
XML函数列表:
XMLSERIALIZE XMLELEMENT XMLATTRIBUTES XMLNAMESPACES XMLFOREST XMLCONCAT XMLAGG
除了 XMLSERIALIZE 之外,其他六个函数均返回 XML 数据类型,包括了元素、属性、命名空间、节点集。利用这些函数提供的 XML 成分,我们可以构造出任意指定的 XML 文档结构。DB2 的 XML 函数已经提供了足够的功能,可以认为只要设计人员能从业务逻辑上实现从关系数据模型到 XML 文档树状结构的映射关系的设计,开发人员就能够利用这些基本函数直接实现 XML 文档的生成。
我们在这里使用简单的示例对上述 XML 函数一一进行介绍。我们在本地数据库中创建了一个简单的 Contact 表,并且插入了几条数据,作为示例基础:
SELECT cust_num, f_name, l_name, email, cnt_num FROM contact
XMLSERIALIZE:
XMLSERIALIZE 函数是一个特殊的函数,并不产生 XML 文档的一部分,而是用于将其他函数产生的 XML 数据类型转化为其他的常见数据类型,如 CHAR、VARCHAR 和 CLOB 等。由于 XML 数据类型不能直接存储到数据库中,也不能直接输出,通常都需要使用 XMLSERIALIZE 函数进行转换,后面的示例也都会使用到它。
XMLELEMENT:
XMLELEMENT 是最基础的 XML 函数,用于构建 XML 元素节点,这个函数接受元素名称和元素内容两个必选参数,另外还可以接受 XML 属性和命名空间参数。元素内容可以是 CHAR、VARCHAR、INT 等基本数据类型,也可以是 XML 元素数据类型,允许 XMLELEMENT 函数的嵌套。
清单1
SELECT
XMLSERIALIZE( CONTENT
XMLELEMENT(NAME "Contact",
XMLELEMENT(NAME "Email", RTRIM(email))
)
AS VARCHAR(5000))
xml FROM contact
where cust_num = '0000000001'
|
XMLATTRIBUTES与XMLNAMESPACES:
XMLATTRIBUTES与XMLNAMESPACES函数的使用方法非常类似,当前者作为参数传给XMLELMENT函数后可以为该元素添加属性,而后者则可以向元素中添加命名空间以及命名空间前缀的声明,多个属性/命名空间可以通过一个XMLATTRIBUTES或XMLNAMESPACES函数一次性添加。
清单2
SELECT
XMLSERIALIZE( CONTENT
XMLELEMENT(NAME "Contact",
XMLNAMESPACES(DEFAULT 'http://www.ibm.com/schemas/DummyDemo',
'http://www.w3.org/2001/XMLSchema' as "xsd"),
XMLATTRIBUTES(cust_num as "CustNo", 1 as "SeqNo"),
XMLELEMENT(NAME "Name",RTRIM(f_name) || ' ' || RTRIM(l_name))
)
AS VARCHAR(5000))
xml FROM contact FETCH FIRST 1 ROWS ONLY
|
XMLFOREST与XMLCONCAT:
XMLFOREST与XMLCONCAT的功能类似,用以生成一组并列的XML元素节点使之具有相同的内部XML数据类型,如<elem1>…</elem1><elem2>…</elem2><elem3>…</elem3>这样的形式。XMLFOREST用于根据输入的多个一般类型值参数生成简单的文本节点"森林",XMLCONCAT接受的参数只能是XML数据类型,可以用于将许多复杂的元素节点组合在一起形成并列的节点结构。
清单3 XMLFOREST与XMLCONCAT对比
SELECT
XMLSERIALIZE( CONTENT
XMLFOREST(
cust_num,
RTRIM(f_name) as "FirstName",
RTRIM(l_name) as "LastName"
)
AS VARCHAR(5000))
xml FROM contact FETCH FIRST 1 ROWS ONLY
|
SELECT
XMLSERIALIZE( CONTENT
XMLCONCAT(
XMLELEMENT(NAME "Name",
XMLATTRIBUTES(RTRIM(cust_num) as "CustNo"),
RTRIM(f_name)|| ' ' || RTRIM(l_name)
),
XMLELEMENT(NAME "Email",RTRIM(email))
)
AS VARCHAR(5000))
xml FROM contact FETCH FIRST 1 ROWS ONLY
|
这两个函数虽然结果形式类似,但是其功能却是不同的。XMLFOREST 只能生成简单值元素的"森林",不能灵活的设置这些值元素的属性和命名空间声明等,但是它语法非常简单,非常适合用在处理多个叶子值节点并列出现的情况。而 XMLCONCAT 能将多个复杂的 XML 元素节点形成并列的节点结构。XMLSERIALIZE 只能接受一个 XML 数据类型的参数,在上述例子中 XMLCONCAT 用来将多个 XML 元素形成并列节点结构并且返回一个相同的 XML 数据类型传给 XMLSERIALIZE,如果不使用 XMLCONCAT 将无法成功调用 XMLSERIALIZE。
XMLAGG:
XMLAGG 是 XML 函数中唯一的聚集函数,XMLAGG 函数可以将若干条记录中的列值按照 XML 结构的定义聚集成为"森林"结构,合成到一条记录中。XMLAGG 为我们根据数据实现动态树状结构提供了基础,是映射关系数据到 XML 文档的重要工具之一。通过 WITH 语句我们还能实现分层聚集、分列聚集这样的功能,但复杂的查询中很可能会产生性能问题。
清单4.1 XMLAGG一般情况
SELECT
XMLSERIALIZE( CONTENT
XMLELEMENT(NAME "Contacts",
XMLATTRIBUTES(cust_num as "CustNo"),
XMLAGG(
XMLELEMENT(NAME "Name",
XMLATTRIBUTES(cnt_num as "ContactNo"),
RTRIM(f_name)|| ' ' || RTRIM(l_name)
) ORDER BY cnt_num
)
)
AS VARCHAR(5000))
xml FROM contact
GROUP BY cust_num
|
先按客户分组再按客户联系人所在城市分组聚集:
清单4.2 XMLAGG 嵌套多层聚集
WITH xmlbase as (SELECT
XMLELEMENT(NAME "City",
XMLATTRIBUTES(RTRIM(city) as "name"),
XMLAGG(
XMLELEMENT(NAME "Contact",
XMLATTRIBUTES(cnt_num as "ContactNo"),
RTRIM(f_name)|| ' ' || RTRIM(l_name)
) ORDER BY cnt_num
)
) xml,cust_num,city FROM contact
GROUP BY cust_num,city)
SELECT XMLSERIALIZE(CONTENT
XMLELEMENT(NAME "CustLoc",
XMLATTRIBUTES(xmlbase.cust_num as "CustNo"),
XMLAGG(xml ORDER BY xmlbase.city)
)
AS VARCHAR(500)) FROM xmlbase
GROUP BY xmlbase.cust_num;
|
加入另一示例表 sold_product,包含客户与产品的联系,在 XML 文档中在每个客户节点下面包含该客户的所有产品信息与所有联系人信息,即将每个客户的产品信息和联系人信息进行并列聚集:
清单4.3 XMLAGG 不同列的聚集
SELECT cust_num, prd_code FROM sold_product;
CUST_NUM PRD_CODE
0000000001 PRODUCT_0A
0000000001 PRODUCT_0B
WITH prd as (
SELECT cust_num,
XMLELEMENT(NAME "Products",
XMLAGG(XMLELEMENT(NAME "Item",prd_code) ORDER BY sp_num)
) xml
FROM sold_product
group by cust_num
),
cnt as (
select cust_num,
XMLELEMENT(NAME "Contacts",
XMLAGG(
XMLELEMENT(NAME "Contact",
XMLATTRIBUTES(contact.cnt_num as "ContactNo"),
RTRIM(f_name)|| ' ' || RTRIM(l_name)
) ORDER BY cnt_num
)
) xml
FROM contact
group by cust_num
)
SELECT
XMLSERIALIZE( CONTENT
XMLELEMENT(NAME "Customer",
XMLATTRIBUTES(prd.cust_num as "CustNo"),
prd.xml,
cnt.xml
)
AS VARCHAR(5000))
xml FROM prd JOIN cnt
ON prd.cust_num=cnt.cust_num
WHERE prd.cust_num='0000000001';
|
2.DB2 示例数据准备与 XML 文档设计
在这里我们将使用一个完整的示例,来展示如何应用这些 XML 函数开发 XML 查询和试图的基本过程。我们所设计的示例希望使用大部分 XML 函数,展示典型应用场景。
在进行 XML 视图的开发之前,我们在前面 contact 示例表的基础上,准备好两个关联的数据表 customer 表与 contact 表,前者与后者是一对多的关系,即一条 customer 记录可以拥有多个联系人记录。
清单5:示例表及数据样例
Customer表
Contact表
我们要将 customer 表中的每一位顾客的信息连同与之相联系的若干 contact 记录通过一个 XML 文档发布,在我们需要实现的 XML 文档结构中必然会出现一个 Customer 元素中包含若干个 contact 元素的树状结构,如图 1 所示。
图1
在通常的开发过程中,我们一般将会被要求根据已定义好的 XSD 文档,来实现指定格式的 XML 文档发布。但 XSD 定义文件并不是必需的,它只是严密地告诉我们目标 XML 文档的结构。实际上编写 XML 查询或视图时,更应该重视 XML 文档样例。因为有很多时候,设计过程可能只提供 XML 文档样例,不过这已经足够了。
在这里为了将示例的目标 XML 文档准确的表达出来,我们也使用 XSD 对其进行定义,编写出定义文件 customer.xsd,如图2所示。
图2 XSD(参见下载中的customer.xsd文件)
customer.xsd 文件中定义了在发布数据客户-联系人信息中所需的若干数据类型和子结构类型,如 LocationType、EmailType、CityType 等,对基本的数据库类型进行了结构化封装,并且规定了 XML 文档的元素层次结构。这里根元素为 CustomerInfo,目标命名空间定义为:"http://www.ibm.com/schemas/SimpleXMLDemo",这个定义文件所形成的 XML 文档结构如图 3 所示。
图3 CustomerInfo 文档结构
图3中红色方框所示的部分说明在一个 CustomerInfo 文档中 Contacts 元素节点下将包含一个或者多个 Contact 子元素,每一个 Contact 子元素包含一位联系人的信息。
现在的 XSD 定义已经涉及到了命名空间的声明,但在此文档中所有的元素及数据类型都属于"http://www.ibm.com/schemas/SimpleXMLDemo"这一命名空间。一个更加普遍的情况是,XML 文件的定义使用了来自不同命名空间的成分,这也是 XML 可重用性的体现。为了模拟这种效果,我们将与 contact 及其子元素有关的所有定义从 customer.xsd 中分离出来放入另一个独立的 XSD 文件 contact.xsd 中去,并且给该文件的命名空间设置为"http://www.ibm.com/schemas/ContactDemo"
图4 分离后文档定义结构(参见下载中的contact.xsd文件)
customer.xsd(contact命名空间前缀声明为cnt):
按照 customer.xsd 文件的定义,我们手工生成一个样本 XML 文档 sample.xml,文档中仅包含一个 Contact 子节点。这样一个完整的 XML 文档样例,在实际的 XML 查询编写过程中会起到非常重要的作用,可以给开发人员一个直观的模板。此外,XML 高度的结构化特点也使利用软件工具来处理变得非常方便。
清单 6 sample.xml
<CustomerInfo xmlns="http://www.ibm.com/schemas/SimpleXMLDemo"
xmlns:cnt="http://www.ibm.com/schemas/ContactDemo"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.ibm.com/schemas/SimpleXMLDemo customer.xsd">
<CustomerID>0000000001</CustomerID>
<CompanyName>Default Company</CompanyName>
<BusinessArea>AP</BusinessArea>
<PrimaryLocation>
<cnt:PostalCode>100088</cnt:PostalCode>
<cnt:AddressLine1>No. 25, Xin Jie Kou Wai
Street.</cnt:AddressLine1>
<cnt:City>Beijing</cnt:City>
<cnt:State>Beijing</cnt:State>
<cnt:Country>RPC</cnt:Country>
</PrimaryLocation>
<Contacts>
<cnt:Contact isPrimary="FALSE" Seq="2">
<cnt:FirstName>Kang</cnt:FirstName>
<cnt:LastName>Yang</cnt:LastName>
<cnt:JobTitle>CIO</cnt:JobTitle>
<cnt:OfficePhone>58808808</cnt:OfficePhone>
<cnt:Cellphone>13100001122</cnt:Cellphone>
<cnt:Fax>58808999</cnt:Fax>
<cnt:Email>yangkang@sina.com</cnt:Email>
<cnt:Location>
<cnt:PostalCode>100745</cnt:PostalCode>
<cnt:AddressLine1>No 123, Wang Fu Jin
Street</cnt:AddressLine1>
<cnt:AddressLine2>No 322, Dummy
Street</cnt:AddressLine2>
<cnt:City>Beijing</cnt:City>
<cnt:State>Beijing</cnt:State>
<cnt:Country>RPC</cnt:Country>
</cnt:Location>
</cnt:Contact>
</Contacts>
</CustomerInfo>
|
当我们得到 XML 示例文档的时候,就可以对照其结构进行 XML 查询或视图的开发了,只需要将 XML 文档中元素与元素的嵌套关系转化为 XMLELEMENT、XMLATTRIBUTES、XMLNAMESPACES 等 XML 函数的嵌套关系。一般的手工修改方法是:将起始标签<element>替换为"XMLELEMENT(NAME "element",";当该元素具有属性或者命名空间声明,需要紧接着加入相应的 XMLATTRIBUTES 或 XMLNAMESPACES 语句;如果这是一个含有文本内容的叶子节点,则要将文本内容修改为 SQL 常量(如:'CONSTANT')或者 SQL 字段(如:tbl.colname);最后把结束标签替换为")",并列的一组元素修改完毕后,应用逗号分隔。为了避免不必要的疏忽,应该遵循嵌套的元素从外到内,并列的元素从前往后的顺序在进行处理。
3.通过工具生成 XML 查询框架
编写 XML 查询的过程如果完全用手工来实施,需要开发者有清晰的思路和良好的编辑习惯,从技术难度上讲没有太多问题,但处理较为复杂的 XML 文档结构时,开发人员需要非常仔细地将 XML 文档中每个元素节点与数据库中的字段进行对应,并且根据样例组织成复杂的 XML 结构,工作量比较大,变得相当麻烦并且容易出错。
作者根据实际开发的 XML 查询的经验,编写了一个小程序,用于将样例 XML 文档转化成 XML 查询框架,即一个可以产生目标结构的 XML 文档 SQL 查询,其中所有的元素、属性值等都直接使用来自样例 XML 中的内容转化为常量。生成的 XML/SQL 查询语句,可以直接在 DB2 中执行,在很大程度上减轻了开发人员的工作量,提高了工作效率。
此程序的代码附于本文后,可供读者下载使用或参考。该程序使用 Java 语言完成,只有一个包含 Main 函数的类:xmlutol.Xml2DB2view,在处理 XML 文件的过程中使用了开源的 dom4j 项目。这个类接受两个参数,前一参数是输入 XML 文档的文件名,后一参数是输出 SQL 脚本的目标文件名。
我们将清单6中的sample.xml传给该程序处理,可以得到初步的 SQL 框架。
清单 7 调用 xmlutol.Xml2DB2view
C:\XML2SQL\java -classpath .\bin;.\lib\dom4j-1.6.1.jar
xmlutol.Xml2DB2view .\input\sample.xml .\output\views.sql
[INFO]:XML to SQL Conversion Finished.
[INFO]:Output file is : .\input\views.sql
|
检查 views.sql 中生成的 SQL 内容:
需要被替换的数据常量用红色粗体标出
清单 8 生成的 views.sql
SELECT XMLSERIALIZE(CONTENT
XMLELEMENT(NAME "CustomerInfo",
XMLNAMESPACES(
DEFAULT 'http://www.ibm.com/schemas/SimpleXMLDemo',
'http://www.ibm.com/schemas/ContactDemo' as "cnt",
'http://www.w3.org/2001/XMLSchema' as "xsd",
'http://www.w3.org/2001/XMLSchema-instance' as "xsi"
),
XMLATTRIBUTES(
'http://www.ibm.com/schemas/SimpleXMLDemo customer.xsd' as "xsi:schemaLocation"
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
),
XMLELEMENT(NAME "CustomerID",
'0000000001'
),
XMLELEMENT(NAME "CompanyName",
'Default Company'
),
XMLELEMENT(NAME "BusinessArea",
'AP'
),
XMLELEMENT(NAME "PrimaryLocation",
XMLELEMENT(NAME "cnt:PostalCode",
'100088'
),
XMLELEMENT(NAME "cnt:AddressLine1",
'No. 25, Xin Jie Kou Wai Street.'
),
XMLELEMENT(NAME "cnt:City",
'Beijing'
),
XMLELEMENT(NAME "cnt:State",
'Beijing'
),
XMLELEMENT(NAME "cnt:Country",
'RPC'
)
),
XMLELEMENT(NAME "Contacts",
XMLELEMENT(NAME "cnt:Contact",
XMLATTRIBUTES(
'FALSE' as "isPrimary",
'2' as "Seq"
),
XMLELEMENT(NAME "cnt:FirstName",
'Kang'
),
XMLELEMENT(NAME "cnt:LastName",
'Yang'
),
XMLELEMENT(NAME "cnt:JobTitle",
'CIO'
),
XMLELEMENT(NAME "cnt:OfficePhone",
'58808808'
),
XMLELEMENT(NAME "cnt:Cellphone",
'13100001122'
),
XMLELEMENT(NAME "cnt:Fax",
'58808999'
),
XMLELEMENT(NAME "cnt:Email",
'yangkang@sina.com'
),
XMLELEMENT(NAME "cnt:Location",
XMLELEMENT(NAME "cnt:PostalCode",
'100745'
),
XMLELEMENT(NAME "cnt:AddressLine1",
'No 123, Wang Fu Jin Street'
),
XMLELEMENT(NAME "cnt:AddressLine2",
'No 322, Dummy Street'
),
XMLELEMENT(NAME "cnt:City",
'Beijing'
),
XMLELEMENT(NAME "cnt:State",
'Beijing'
),
XMLELEMENT(NAME "cnt:Country",
'RPC'
)
)
)
)
)
as VARCHAR(5000)) FROM sysibm.sysdummy1;
|
在接下来的过程中,需要将查询中的引用的 sysibm.sysdummy1 表、常数内容等替换成目标表和相应的数据列,如果需要还应该加入聚集、Null 值处理等逻辑, 以及使用 XMLFOREST 函数对查询进行精简。由于这些修改非常灵活,而且对于每个任务可能会很特殊,所以不便用简单的程序来实现,所幸这部分修改的工作量相对较小。
4.修改 XML 框架完成 XML 查询
以清单 8 中的查询脚本为基础,通过适当的修改,就可以完成发布 Customer 与 Contact 数据的 XML 查询。
在得到 XML 查询框架之后,就应写出读取目标数据的常规 SQL,如果觉得有必要还可以根据此查询整理出从查询数据列到 XML 文档元素的映射关系列表,方便后续的修改。
清单 10 SQL 常规查询,及其 XML 映射关系
SELECT
--customer columns
cust.cust_num,cust.cust_name,cust.language,
cust.area,cust.address,cust.city,
cust.state,cust.postal_code,cust.country_code,
--contact columns
cnt.cnt_num,cnt.f_name,cnt.l_name,
cnt.title,cnt.office_phone,cnt.cellphone,
cnt.fax,cnt.email,cnt.address,
cnt.address2,cnt.city,cnt.state,
cnt.postal_code,cnt.country_code,cnt.prim_flag
FROM
customer cust
JOIN contact cnt
ON cust.cust_num = cnt.cust_num
|
根据上面的列表,我们逐一将 XML 查询框架中的常量用 SQL 查询的字段替换,同时也用 SQL 查询的 From 语句块替换掉 XML 查询框架的"FROM sysibm.sysdummy1"部分。
聚集处理:
将这个查询应用入 XML 查询时,由于 customer 与 contact 是一对多的关系,根据设计 XML 查询中的单条记录对应一条 customer 记录,所以我们需要在 XML 查询中对来自 contact 表的部分进行聚集,即对 <cnt:Contact> 元素进行聚集。
清单 11 <cnt:Contact> 聚集片断
SELECT ……
XMLAGG(
XMLELEMENT(NAME "cnt:Contact",
……
……
) ORDER BY cnt.cnt_num
) ……
FROM ……
……
Group by cnt.cnt_num, ……
|
NULL 值处理:
通常情况下,XML文档中某些可选元素的源数据在数据库中可能为空值,而XMLELEMENT函数接收NULL值,会在XML文档中产生形如<Element></Element>的空节点。对于XML文档的处理时,我们一般不希望显示这样的空节点。对于这样的情况,可以通过清单12的方式进行处理。
清单12 NULL 值处理
XMLELEMENT(NAME "cnt:Location",
XMLELEMENT(NAME "cnt:AddressLine1",
cnt.address
),
CASE
WHEN RTRIM(COALESCE(cnt.address2,''))<>'' THEN
XMLELEMENT(NAME "cnt:AddressLine2",
cnt.address2
)
ELSE NULL END
)
|
当 cnt.address2 为空值时,上述的语句中的"cnt:AddressLine2"节点将不会出现在生成的 XML 中,XML 结构将是:
<cnt:Location><cnt:AddressLine1>4F, Sunshine Building</cnt:Location>
</cnt:AddressLine1>
|
如果有很多可选节点,也可以通过程序来生成框架,只需要给样例 XML 文档的相应节点添加 optional 属性并赋为"true",譬如 <BusinessArea optional="true">AP</BusinessArea>,通过我们的程序即可完成对其的处理。
经过上述修改就完成了最终的 XML 查询语句,在清单 13 中,已把在生成的 XML 查询框架基础上的修改用蓝色粗体标注出来,其中 BusinessArea,cnt:JobTitle,cnt:Cellphone,cnt:Location ,cnt:Fax 和 cnt:AddressLine2 元素为可选节点。
清单13 最终 XML 查询
SELECT XMLSERIALIZE(CONTENT
XMLELEMENT(NAME "CustomerInfo",
XMLNAMESPACES(
DEFAULT 'http://www.ibm.com/schemas/SimpleXMLDemo',
'http://www.ibm.com/schemas/ContactDemo' as "cnt",
'http://www.w3.org/2001/XMLSchema' as "xsd",
'http://www.w3.org/2001/XMLSchema-instance' as "xsi"
),
XMLATTRIBUTES(
'http://www.ibm.com/schemas/SimpleXMLDemo customer2.xsd' as "xsi:schemaLocation"
|-------- XML error: The previous line is longer than the max of 90 characters ---------|
),
XMLELEMENT(NAME "CustomerID",
cust.cust_num
),
XMLELEMENT(NAME "CompanyName",
cust.cust_name
),
CASE
WHEN RTRIM(COALESCE(cust.area,''))<>'' THEN
XMLELEMENT(NAME "BusinessArea",
cust.area
)
ELSE NULL END,
XMLELEMENT(NAME "PrimaryLocation",
XMLELEMENT(NAME "cnt:PostalCode",
cust.postal_code
),
XMLELEMENT(NAME "cnt:AddressLine1",
cust.address
),
XMLELEMENT(NAME "cnt:City",
cust.city
),
XMLELEMENT(NAME "cnt:State",
cust.state
),
XMLELEMENT(NAME "cnt:Country",
cust.country_code
)
),
XMLELEMENT(NAME "Contacts",
XMLAGG(
XMLELEMENT(NAME "cnt:Contact",
XMLATTRIBUTES(
(CASE
WHEN cnt.prim_flag=1 THEN 'TRUE'
ELSE 'FALSE' END) as "isPrimary",
cnt.cnt_num as "Seq"
),
XMLELEMENT(NAME "cnt:FirstName",
cnt.f_name
),
XMLELEMENT(NAME "cnt:LastName",
cnt.l_name
),
CASE
WHEN RTRIM(COALESCE(cnt.title,''))<>'' THEN
XMLELEMENT(NAME "cnt:JobTitle",
cnt.title
)
ELSE NULL END,
XMLELEMENT(NAME "cnt:OfficePhone",
cnt.office_phone
),
CASE
WHEN RTRIM(COALESCE(cnt.cellphone,''))<>'' THEN
XMLELEMENT(NAME "cnt:Cellphone",
cnt.cellphone
)
ELSE NULL END,
CASE
WHEN RTRIM(COALESCE(cnt.fax,''))<>'' THEN
XMLELEMENT(NAME "cnt:Fax",
cnt.fax
)
ELSE NULL END,
XMLELEMENT(NAME "cnt:Email",
cnt.email
),
CASE
WHEN RTRIM(COALESCE(cnt.address,''))<>'' THEN
XMLELEMENT(NAME "cnt:Location",
XMLELEMENT(NAME "cnt:PostalCode",
cnt.postal_code
),
XMLELEMENT(NAME "cnt:AddressLine1",
cnt.address
),
CASE
WHEN RTRIM(COALESCE(cnt.address2,''))<>'' THEN
XMLELEMENT(NAME "cnt:AddressLine2",
cnt.address2
)
ELSE NULL END,
XMLELEMENT(NAME "cnt:City",
cnt.city
),
XMLELEMENT(NAME "cnt:State",
cnt.state
),
XMLELEMENT(NAME "cnt:Country",
cnt.country_code
)
)
ELSE NULL END
) ORDER BY cnt.cnt_num
)
)
)
as VARCHAR(5000)) FROM
customer cust
JOIN contact cnt
ON cust.cust_num = cnt.cust_num
GROUP BY
cust.cust_num,cust.cust_name,cust.language,
cust.area,cust.address,cust.city,
cust.state,cust.postal_code,cust.country_code
;
|
根据这个查询得到 XML 文档,参见下载中的 result.xml。
总结
本文主要介绍了 DB2 提供的基本的 XML 函数,并且给出了具体的开发实例,读者可以通过本文了解如何根据 XSD 文档或者 XML 样例进行试图和查询的开发。另外,DB2 Extender 提供了更为方便的创建 XML 视图或查询的功能,但是一般情况下需要对现有数据库进行升级和配置。而在一个产品的生命周期中,会存在多个数据库服务器作为开发、测试、维护和产品运行所使用。为这些数据库增加 Extender 功能会增加 DBA 的工作量,还会增加产品环境停止服务的时间。但是通过本文的介绍,并结合笔者开发的工具使用,只利用 DB2 提供的基本 XML 函数,同样可以很方便快捷的开发 XML 视图和查询。
下载
名字 |
大小 |
下载方法 |
0609zhangdw.zip |
298K |
HTTP
|
作者简介
|
|
|
陈力,北京师范大学信息管理专业研究生,在IBM CSDL Beijing的DSW ODS组实习。熟悉DB2,J2EE等技术,对Web应用、Web Services以及Java技术很感兴趣。
|
|
|
|
张大为,IBM CSDL 软件工程师. 目前从事DB2相关工作,主要对电子商务应用进行数据支持。对DB2、Unix、Web Services以及Java技术很感兴趣。
|
|