級別: 初級
陳 力
(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技術很感興趣。
|
|