<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    空間站

    北極心空

      BlogJava :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
      15 Posts :: 393 Stories :: 160 Comments :: 0 Trackbacks

    級(jí)別: 初級(jí)

    陳 力 (chenli44@yeah.net), 北京師范大學(xué)信息管理專業(yè)研究生
    張 大為 (zhangdaw@cn.ibm.com), 軟件工程師

    2006 年 9 月 21 日

    摘要:本文將介紹 DB2 提供的一些基本 XML 函數(shù),并結(jié)合一個(gè)簡(jiǎn)單的實(shí)例,重點(diǎn)介紹如何利用 DB2 提供的 XML 函數(shù)以視圖或查詢的形式靈活的實(shí)現(xiàn) XML 文檔的構(gòu)造和發(fā)布。

    DB2 提供了豐富的功能用以發(fā)布 XML 格式的數(shù)據(jù),這種功能包括了 DB2 內(nèi)置的 XML 函數(shù)以及 XML extender 提供的功能(包括了發(fā)布、解析、檢索、存儲(chǔ)等多種功能)。對(duì) XML 文檔的支持,使得利用現(xiàn)有的 DB2 數(shù)據(jù)庫(kù),就能夠方便的實(shí)現(xiàn)系統(tǒng)或者數(shù)據(jù)的整合。

    本文讀者定位為具有一定的 DB2 開發(fā)經(jīng)驗(yàn),同時(shí)對(duì) XML 語(yǔ)言的格式、schema 定義、命名空間等有基本的理解。

    本文將介紹 DB2 提供的一些基本 XML 函數(shù),并結(jié)合一個(gè)簡(jiǎn)單的實(shí)例,重點(diǎn)介紹如何利用 DB2 提供的 XML 函數(shù)以視圖或查詢的形式靈活的實(shí)現(xiàn) XML 文檔的構(gòu)造和發(fā)布。同時(shí)文中還將介紹利用作者編制的一個(gè)工具,根據(jù)目標(biāo) XML 的樣例文檔生成相應(yīng)的包含 XML 函數(shù)的查詢框架,以輔助開發(fā)較為復(fù)雜的 XML 文檔結(jié)構(gòu)的 SQL 語(yǔ)句。

    以 DB2 的 XML 函數(shù)為基礎(chǔ)的 SQL 語(yǔ)句支持 XML 語(yǔ)言的絕大部分特征,可以簡(jiǎn)單而直觀地實(shí)現(xiàn)從關(guān)系型數(shù)據(jù)模型到 XML 的樹狀結(jié)構(gòu)的轉(zhuǎn)換,其靈活性接近于手工書寫 XML 文檔,同時(shí),只要利用適當(dāng)?shù)姆椒ê凸ぞ撸涂梢栽诓辉黾娱_發(fā)復(fù)雜度的基礎(chǔ)上大大降低開發(fā)的工作量。

    1.DB2 XML 查詢/視圖及 XML 函數(shù)簡(jiǎn)介

    利用 XML 函數(shù)我們可以方便的構(gòu)建 XML 查詢或視圖,利用這些函數(shù)發(fā)布 XML 的整個(gè)過(guò)程與開發(fā)和使用傳統(tǒng)的查詢與視圖并沒(méi)有本質(zhì)的區(qū)別。XML 查詢不需要依賴于復(fù)雜的發(fā)布程序和軟件平臺(tái),即使只有 DB2 命令行客戶端,我們也能夠連接數(shù)據(jù)庫(kù)發(fā)布 XML 文檔。可見利用這種方式進(jìn)行 XML 發(fā)布具有很廣泛的應(yīng)用范圍,能夠適應(yīng)從高級(jí)語(yǔ)言開發(fā)的網(wǎng)絡(luò)程序到簡(jiǎn)單的 Shell 腳本這樣不同級(jí)別實(shí)現(xiàn)的要求,而且特別有利于簡(jiǎn)單直接的解決方案。這給我們以 DB2 數(shù)據(jù)庫(kù)為基礎(chǔ)實(shí)現(xiàn)異構(gòu)數(shù)據(jù)系統(tǒng)的整合與互動(dòng)功能提供了一個(gè)簡(jiǎn)便易行的方法。

    DB2 UDB 8.2 直接提供了 7 種 SQL/XML 函數(shù),以及與這些 XML 語(yǔ)法成分對(duì)應(yīng)的 XML 數(shù)據(jù)類型。

    XML函數(shù)列表:

    XMLSERIALIZE
    XMLELEMENT
    XMLATTRIBUTES
    XMLNAMESPACES
    XMLFOREST
    XMLCONCAT
    XMLAGG

    除了 XMLSERIALIZE 之外,其他六個(gè)函數(shù)均返回 XML 數(shù)據(jù)類型,包括了元素、屬性、命名空間、節(jié)點(diǎn)集。利用這些函數(shù)提供的 XML 成分,我們可以構(gòu)造出任意指定的 XML 文檔結(jié)構(gòu)。DB2 的 XML 函數(shù)已經(jīng)提供了足夠的功能,可以認(rèn)為只要設(shè)計(jì)人員能從業(yè)務(wù)邏輯上實(shí)現(xiàn)從關(guān)系數(shù)據(jù)模型到 XML 文檔樹狀結(jié)構(gòu)的映射關(guān)系的設(shè)計(jì),開發(fā)人員就能夠利用這些基本函數(shù)直接實(shí)現(xiàn) XML 文檔的生成。

    我們?cè)谶@里使用簡(jiǎn)單的示例對(duì)上述 XML 函數(shù)一一進(jìn)行介紹。我們?cè)诒镜財(cái)?shù)據(jù)庫(kù)中創(chuàng)建了一個(gè)簡(jiǎn)單的 Contact 表,并且插入了幾條數(shù)據(jù),作為示例基礎(chǔ):


    SELECT cust_num, f_name, l_name, email, cnt_num FROM contact
    SELECT cust_num, f_name, l_name, email, cnt_num FROM contact

    XMLSERIALIZE:

    XMLSERIALIZE 函數(shù)是一個(gè)特殊的函數(shù),并不產(chǎn)生 XML 文檔的一部分,而是用于將其他函數(shù)產(chǎn)生的 XML 數(shù)據(jù)類型轉(zhuǎn)化為其他的常見數(shù)據(jù)類型,如 CHAR、VARCHAR 和 CLOB 等。由于 XML 數(shù)據(jù)類型不能直接存儲(chǔ)到數(shù)據(jù)庫(kù)中,也不能直接輸出,通常都需要使用 XMLSERIALIZE 函數(shù)進(jìn)行轉(zhuǎn)換,后面的示例也都會(huì)使用到它。

    XMLELEMENT:

    XMLELEMENT 是最基礎(chǔ)的 XML 函數(shù),用于構(gòu)建 XML 元素節(jié)點(diǎn),這個(gè)函數(shù)接受元素名稱和元素內(nèi)容兩個(gè)必選參數(shù),另外還可以接受 XML 屬性和命名空間參數(shù)。元素內(nèi)容可以是 CHAR、VARCHAR、INT 等基本數(shù)據(jù)類型,也可以是 XML 元素?cái)?shù)據(jù)類型,允許 XMLELEMENT 函數(shù)的嵌套。


    清單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函數(shù)的使用方法非常類似,當(dāng)前者作為參數(shù)傳給XMLELMENT函數(shù)后可以為該元素添加屬性,而后者則可以向元素中添加命名空間以及命名空間前綴的聲明,多個(gè)屬性/命名空間可以通過(guò)一個(gè)XMLATTRIBUTES或XMLNAMESPACES函數(shù)一次性添加。


    清單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元素節(jié)點(diǎn)使之具有相同的內(nèi)部XML數(shù)據(jù)類型,如<elem1>…</elem1><elem2>…</elem2><elem3>…</elem3>這樣的形式。XMLFOREST用于根據(jù)輸入的多個(gè)一般類型值參數(shù)生成簡(jiǎn)單的文本節(jié)點(diǎn)"森林",XMLCONCAT接受的參數(shù)只能是XML數(shù)據(jù)類型,可以用于將許多復(fù)雜的元素節(jié)點(diǎn)組合在一起形成并列的節(jié)點(diǎn)結(jié)構(gòu)。


    清單3 XMLFOREST與XMLCONCAT對(duì)比
    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
    



    這兩個(gè)函數(shù)雖然結(jié)果形式類似,但是其功能卻是不同的。XMLFOREST 只能生成簡(jiǎn)單值元素的"森林",不能靈活的設(shè)置這些值元素的屬性和命名空間聲明等,但是它語(yǔ)法非常簡(jiǎn)單,非常適合用在處理多個(gè)葉子值節(jié)點(diǎn)并列出現(xiàn)的情況。而 XMLCONCAT 能將多個(gè)復(fù)雜的 XML 元素節(jié)點(diǎn)形成并列的節(jié)點(diǎn)結(jié)構(gòu)。XMLSERIALIZE 只能接受一個(gè) XML 數(shù)據(jù)類型的參數(shù),在上述例子中 XMLCONCAT 用來(lái)將多個(gè) XML 元素形成并列節(jié)點(diǎn)結(jié)構(gòu)并且返回一個(gè)相同的 XML 數(shù)據(jù)類型傳給 XMLSERIALIZE,如果不使用 XMLCONCAT 將無(wú)法成功調(diào)用 XMLSERIALIZE。

    XMLAGG:

    XMLAGG 是 XML 函數(shù)中唯一的聚集函數(shù),XMLAGG 函數(shù)可以將若干條記錄中的列值按照 XML 結(jié)構(gòu)的定義聚集成為"森林"結(jié)構(gòu),合成到一條記錄中。XMLAGG 為我們根據(jù)數(shù)據(jù)實(shí)現(xiàn)動(dòng)態(tài)樹狀結(jié)構(gòu)提供了基礎(chǔ),是映射關(guān)系數(shù)據(jù)到 XML 文檔的重要工具之一。通過(guò) WITH 語(yǔ)句我們還能實(shí)現(xiàn)分層聚集、分列聚集這樣的功能,但復(fù)雜的查詢中很可能會(huì)產(chǎn)生性能問(wèn)題。


    清單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
    



    先按客戶分組再按客戶聯(lián)系人所在城市分組聚集:


    清單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,包含客戶與產(chǎn)品的聯(lián)系,在 XML 文檔中在每個(gè)客戶節(jié)點(diǎn)下面包含該客戶的所有產(chǎn)品信息與所有聯(lián)系人信息,即將每個(gè)客戶的產(chǎn)品信息和聯(lián)系人信息進(jìn)行并列聚集:


    清單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';
    







    回頁(yè)首


    2.DB2 示例數(shù)據(jù)準(zhǔn)備與 XML 文檔設(shè)計(jì)

    在這里我們將使用一個(gè)完整的示例,來(lái)展示如何應(yīng)用這些 XML 函數(shù)開發(fā) XML 查詢和試圖的基本過(guò)程。我們所設(shè)計(jì)的示例希望使用大部分 XML 函數(shù),展示典型應(yīng)用場(chǎng)景。

    在進(jìn)行 XML 視圖的開發(fā)之前,我們?cè)谇懊?contact 示例表的基礎(chǔ)上,準(zhǔn)備好兩個(gè)關(guān)聯(lián)的數(shù)據(jù)表 customer 表與 contact 表,前者與后者是一對(duì)多的關(guān)系,即一條 customer 記錄可以擁有多個(gè)聯(lián)系人記錄。

    清單5:示例表及數(shù)據(jù)樣例


    Customer表
    Customer表

    Contact表
    Contact表

    我們要將 customer 表中的每一位顧客的信息連同與之相聯(lián)系的若干 contact 記錄通過(guò)一個(gè) XML 文檔發(fā)布,在我們需要實(shí)現(xiàn)的 XML 文檔結(jié)構(gòu)中必然會(huì)出現(xiàn)一個(gè) Customer 元素中包含若干個(gè) contact 元素的樹狀結(jié)構(gòu),如圖 1 所示。


    圖1
    圖1

    在通常的開發(fā)過(guò)程中,我們一般將會(huì)被要求根據(jù)已定義好的 XSD 文檔,來(lái)實(shí)現(xiàn)指定格式的 XML 文檔發(fā)布。但 XSD 定義文件并不是必需的,它只是嚴(yán)密地告訴我們目標(biāo) XML 文檔的結(jié)構(gòu)。實(shí)際上編寫 XML 查詢或視圖時(shí),更應(yīng)該重視 XML 文檔樣例。因?yàn)橛泻芏鄷r(shí)候,設(shè)計(jì)過(guò)程可能只提供 XML 文檔樣例,不過(guò)這已經(jīng)足夠了。

    在這里為了將示例的目標(biāo) XML 文檔準(zhǔn)確的表達(dá)出來(lái),我們也使用 XSD 對(duì)其進(jìn)行定義,編寫出定義文件 customer.xsd,如圖2所示。

    圖2 XSD(參見下載中的customer.xsd文件)



    customer.xsd 文件中定義了在發(fā)布數(shù)據(jù)客戶-聯(lián)系人信息中所需的若干數(shù)據(jù)類型和子結(jié)構(gòu)類型,如 LocationType、EmailType、CityType 等,對(duì)基本的數(shù)據(jù)庫(kù)類型進(jìn)行了結(jié)構(gòu)化封裝,并且規(guī)定了 XML 文檔的元素層次結(jié)構(gòu)。這里根元素為 CustomerInfo,目標(biāo)命名空間定義為:"http://www.ibm.com/schemas/SimpleXMLDemo",這個(gè)定義文件所形成的 XML 文檔結(jié)構(gòu)如圖 3 所示。


    圖3 CustomerInfo 文檔結(jié)構(gòu)
    圖3  CustomerInfo 文檔結(jié)構(gòu)

    圖3中紅色方框所示的部分說(shuō)明在一個(gè) CustomerInfo 文檔中 Contacts 元素節(jié)點(diǎn)下將包含一個(gè)或者多個(gè) Contact 子元素,每一個(gè) Contact 子元素包含一位聯(lián)系人的信息。

    現(xiàn)在的 XSD 定義已經(jīng)涉及到了命名空間的聲明,但在此文檔中所有的元素及數(shù)據(jù)類型都屬于"http://www.ibm.com/schemas/SimpleXMLDemo"這一命名空間。一個(gè)更加普遍的情況是,XML 文件的定義使用了來(lái)自不同命名空間的成分,這也是 XML 可重用性的體現(xiàn)。為了模擬這種效果,我們將與 contact 及其子元素有關(guān)的所有定義從 customer.xsd 中分離出來(lái)放入另一個(gè)獨(dú)立的 XSD 文件 contact.xsd 中去,并且給該文件的命名空間設(shè)置為"http://www.ibm.com/schemas/ContactDemo"

    圖4 分離后文檔定義結(jié)構(gòu)(參見下載中的contact.xsd文件)



    customer.xsd(contact命名空間前綴聲明為cnt):



    按照 customer.xsd 文件的定義,我們手工生成一個(gè)樣本 XML 文檔 sample.xml,文檔中僅包含一個(gè) Contact 子節(jié)點(diǎn)。這樣一個(gè)完整的 XML 文檔樣例,在實(shí)際的 XML 查詢編寫過(guò)程中會(huì)起到非常重要的作用,可以給開發(fā)人員一個(gè)直觀的模板。此外,XML 高度的結(jié)構(gòu)化特點(diǎn)也使利用軟件工具來(lái)處理變得非常方便。


    清單 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>
    

    當(dāng)我們得到 XML 示例文檔的時(shí)候,就可以對(duì)照其結(jié)構(gòu)進(jìn)行 XML 查詢或視圖的開發(fā)了,只需要將 XML 文檔中元素與元素的嵌套關(guān)系轉(zhuǎn)化為 XMLELEMENT、XMLATTRIBUTES、XMLNAMESPACES 等 XML 函數(shù)的嵌套關(guān)系。一般的手工修改方法是:將起始標(biāo)簽<element>替換為"XMLELEMENT(NAME "element",";當(dāng)該元素具有屬性或者命名空間聲明,需要緊接著加入相應(yīng)的 XMLATTRIBUTES 或 XMLNAMESPACES 語(yǔ)句;如果這是一個(gè)含有文本內(nèi)容的葉子節(jié)點(diǎn),則要將文本內(nèi)容修改為 SQL 常量(如:'CONSTANT')或者 SQL 字段(如:tbl.colname);最后把結(jié)束標(biāo)簽替換為")",并列的一組元素修改完畢后,應(yīng)用逗號(hào)分隔。為了避免不必要的疏忽,應(yīng)該遵循嵌套的元素從外到內(nèi),并列的元素從前往后的順序在進(jìn)行處理。





    回頁(yè)首


    3.通過(guò)工具生成 XML 查詢框架

    編寫 XML 查詢的過(guò)程如果完全用手工來(lái)實(shí)施,需要開發(fā)者有清晰的思路和良好的編輯習(xí)慣,從技術(shù)難度上講沒(méi)有太多問(wèn)題,但處理較為復(fù)雜的 XML 文檔結(jié)構(gòu)時(shí),開發(fā)人員需要非常仔細(xì)地將 XML 文檔中每個(gè)元素節(jié)點(diǎn)與數(shù)據(jù)庫(kù)中的字段進(jìn)行對(duì)應(yīng),并且根據(jù)樣例組織成復(fù)雜的 XML 結(jié)構(gòu),工作量比較大,變得相當(dāng)麻煩并且容易出錯(cuò)。

    作者根據(jù)實(shí)際開發(fā)的 XML 查詢的經(jīng)驗(yàn),編寫了一個(gè)小程序,用于將樣例 XML 文檔轉(zhuǎn)化成 XML 查詢框架,即一個(gè)可以產(chǎn)生目標(biāo)結(jié)構(gòu)的 XML 文檔 SQL 查詢,其中所有的元素、屬性值等都直接使用來(lái)自樣例 XML 中的內(nèi)容轉(zhuǎn)化為常量。生成的 XML/SQL 查詢語(yǔ)句,可以直接在 DB2 中執(zhí)行,在很大程度上減輕了開發(fā)人員的工作量,提高了工作效率。

    此程序的代碼附于本文后,可供讀者下載使用或參考。該程序使用 Java 語(yǔ)言完成,只有一個(gè)包含 Main 函數(shù)的類:xmlutol.Xml2DB2view,在處理 XML 文件的過(guò)程中使用了開源的 dom4j 項(xiàng)目。這個(gè)類接受兩個(gè)參數(shù),前一參數(shù)是輸入 XML 文檔的文件名,后一參數(shù)是輸出 SQL 腳本的目標(biāo)文件名。

    我們將清單6中的sample.xml傳給該程序處理,可以得到初步的 SQL 框架。


    清單 7 調(diào)用 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 內(nèi)容:

    需要被替換的數(shù)據(jù)常量用紅色粗體標(biāo)出


    清單 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;
    

    在接下來(lái)的過(guò)程中,需要將查詢中的引用的 sysibm.sysdummy1 表、常數(shù)內(nèi)容等替換成目標(biāo)表和相應(yīng)的數(shù)據(jù)列,如果需要還應(yīng)該加入聚集、Null 值處理等邏輯, 以及使用 XMLFOREST 函數(shù)對(duì)查詢進(jìn)行精簡(jiǎn)。由于這些修改非常靈活,而且對(duì)于每個(gè)任務(wù)可能會(huì)很特殊,所以不便用簡(jiǎn)單的程序來(lái)實(shí)現(xiàn),所幸這部分修改的工作量相對(duì)較小。





    回頁(yè)首


    4.修改 XML 框架完成 XML 查詢

    以清單 8 中的查詢腳本為基礎(chǔ),通過(guò)適當(dāng)?shù)男薷模涂梢酝瓿砂l(fā)布 Customer 與 Contact 數(shù)據(jù)的 XML 查詢。

    在得到 XML 查詢框架之后,就應(yīng)寫出讀取目標(biāo)數(shù)據(jù)的常規(guī) SQL,如果覺得有必要還可以根據(jù)此查詢整理出從查詢數(shù)據(jù)列到 XML 文檔元素的映射關(guān)系列表,方便后續(xù)的修改。


    清單 10 SQL 常規(guī)查詢,及其 XML 映射關(guān)系
    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



    根據(jù)上面的列表,我們逐一將 XML 查詢框架中的常量用 SQL 查詢的字段替換,同時(shí)也用 SQL 查詢的 From 語(yǔ)句塊替換掉 XML 查詢框架的"FROM sysibm.sysdummy1"部分。

    聚集處理:

    將這個(gè)查詢應(yīng)用入 XML 查詢時(shí),由于 customer 與 contact 是一對(duì)多的關(guān)系,根據(jù)設(shè)計(jì) XML 查詢中的單條記錄對(duì)應(yīng)一條 customer 記錄,所以我們需要在 XML 查詢中對(duì)來(lái)自 contact 表的部分進(jìn)行聚集,即對(duì) <cnt:Contact> 元素進(jìn)行聚集。


    清單 11 <cnt:Contact> 聚集片斷
    SELECT ……
    XMLAGG(
    XMLELEMENT(NAME "cnt:Contact",
    ……
    ……
    ) ORDER BY cnt.cnt_num
    ) ……
    FROM ……
    ……
    Group by cnt.cnt_num, ……
    

    NULL 值處理:

    通常情況下,XML文檔中某些可選元素的源數(shù)據(jù)在數(shù)據(jù)庫(kù)中可能為空值,而XMLELEMENT函數(shù)接收NULL值,會(huì)在XML文檔中產(chǎn)生形如<Element></Element>的空節(jié)點(diǎn)。對(duì)于XML文檔的處理時(shí),我們一般不希望顯示這樣的空節(jié)點(diǎn)。對(duì)于這樣的情況,可以通過(guò)清單12的方式進(jìn)行處理。


    清單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
    )
    

    當(dāng) cnt.address2 為空值時(shí),上述的語(yǔ)句中的"cnt:AddressLine2"節(jié)點(diǎn)將不會(huì)出現(xiàn)在生成的 XML 中,XML 結(jié)構(gòu)將是:


    <cnt:Location><cnt:AddressLine1>4F, Sunshine Building</cnt:Location>
    </cnt:AddressLine1>
    

    如果有很多可選節(jié)點(diǎn),也可以通過(guò)程序來(lái)生成框架,只需要給樣例 XML 文檔的相應(yīng)節(jié)點(diǎn)添加 optional 屬性并賦為"true",譬如 <BusinessArea optional="true">AP</BusinessArea>,通過(guò)我們的程序即可完成對(duì)其的處理。

    經(jīng)過(guò)上述修改就完成了最終的 XML 查詢語(yǔ)句,在清單 13 中,已把在生成的 XML 查詢框架基礎(chǔ)上的修改用藍(lán)色粗體標(biāo)注出來(lái),其中 BusinessArea,cnt:JobTitle,cnt:Cellphone,cnt:Location ,cnt:Fax 和 cnt:AddressLine2 元素為可選節(jié)點(diǎn)。


    清單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
    ;
    

    根據(jù)這個(gè)查詢得到 XML 文檔,參見下載中的 result.xml。





    回頁(yè)首


    總結(jié)

    本文主要介紹了 DB2 提供的基本的 XML 函數(shù),并且給出了具體的開發(fā)實(shí)例,讀者可以通過(guò)本文了解如何根據(jù) XSD 文檔或者 XML 樣例進(jìn)行試圖和查詢的開發(fā)。另外,DB2 Extender 提供了更為方便的創(chuàng)建 XML 視圖或查詢的功能,但是一般情況下需要對(duì)現(xiàn)有數(shù)據(jù)庫(kù)進(jìn)行升級(jí)和配置。而在一個(gè)產(chǎn)品的生命周期中,會(huì)存在多個(gè)數(shù)據(jù)庫(kù)服務(wù)器作為開發(fā)、測(cè)試、維護(hù)和產(chǎn)品運(yùn)行所使用。為這些數(shù)據(jù)庫(kù)增加 Extender 功能會(huì)增加 DBA 的工作量,還會(huì)增加產(chǎn)品環(huán)境停止服務(wù)的時(shí)間。但是通過(guò)本文的介紹,并結(jié)合筆者開發(fā)的工具使用,只利用 DB2 提供的基本 XML 函數(shù),同樣可以很方便快捷的開發(fā) XML 視圖和查詢。






    回頁(yè)首


    下載

    名字 大小 下載方法
    0609zhangdw.zip 298K HTTP
    關(guān)于下載方法的信息 Get Adobe? Reader?




    回頁(yè)首






    回頁(yè)首


    作者簡(jiǎn)介

    陳力,北京師范大學(xué)信息管理專業(yè)研究生,在IBM CSDL Beijing的DSW ODS組實(shí)習(xí)。熟悉DB2,J2EE等技術(shù),對(duì)Web應(yīng)用、Web Services以及Java技術(shù)很感興趣。


    張大為,IBM CSDL 軟件工程師. 目前從事DB2相關(guān)工作,主要對(duì)電子商務(wù)應(yīng)用進(jìn)行數(shù)據(jù)支持。對(duì)DB2、Unix、Web Services以及Java技術(shù)很感興趣。

    posted on 2006-11-27 18:10 蘆葦 閱讀(1641) 評(píng)論(0)  編輯  收藏 所屬分類: 其他
    主站蜘蛛池模板: 在线综合亚洲欧洲综合网站| 亚洲欧洲日韩不卡| 久久久久亚洲国产AV麻豆| 中文字幕无码不卡免费视频| 国产精品亚洲片在线va| 成人男女网18免费视频| 亚洲JIZZJIZZ妇女| 免费人成年激情视频在线观看| 国产午夜亚洲精品不卡| 亚洲国产黄在线观看| 国产精品美女久久久免费| 亚洲成色在线综合网站| 免费国产污网站在线观看15| 亚洲国产成人精品无码一区二区| 久久久久久国产a免费观看黄色大片| 亚洲人成人网毛片在线播放| 免费看AV毛片一区二区三区| 暖暖免费中文在线日本| 亚洲欧洲成人精品香蕉网| 97免费人妻在线视频| 亚洲日韩看片无码电影| 亚洲精品视频免费| 无码精品一区二区三区免费视频| 亚洲成a人片在线观看中文app| 日本牲交大片免费观看| 中文字幕看片在线a免费| 亚洲一区中文字幕久久| 麻豆精品国产免费观看| 成年女人A毛片免费视频| 亚洲六月丁香六月婷婷色伊人| 日本人的色道www免费一区| 成人网站免费大全日韩国产 | 四虎永久在线精品免费一区二区 | 国内精自视频品线六区免费| 亚洲AV成人精品一区二区三区| 激情97综合亚洲色婷婷五| 国产精品成人免费福利| av电影在线免费看| 亚洲看片无码在线视频 | 亚洲综合色区在线观看| 91成人免费在线视频|