當行與列不能滿足需要時
2024-07-21 02:33:59
供稿:網(wǎng)友
使用原生xml(native XML)特性處理不斷變化的數(shù)據(jù)結(jié)構(gòu)。
在處理不完全符合關(guān)系模型要求的數(shù)據(jù)或者應(yīng)用程序必須處理隨時間而改變的數(shù)據(jù)結(jié)構(gòu)時,你會怎么做呢?
在本專欄中,我將闡明我是如何使用Oracle XML DB的特性來創(chuàng)建一個原型系統(tǒng)的,它無需重新編碼便能適應(yīng)新的及改變了的數(shù)據(jù)結(jié)構(gòu)。我還將介紹Oracle的DevTrends網(wǎng)站上的工作示例代碼。
Oracle XML DB是Oracle9i第二版(9.2.0.2或更高版)的一組特性,它為存儲、定位和查詢XML文檔提供了原生支持。
應(yīng)用程序要求
該原型系統(tǒng)將存儲并轉(zhuǎn)發(fā)政府機構(gòu)所使用的治理文檔(表格、狀態(tài)報告、簡報等)。很興奮這些文檔將用XML進行編碼。但仍存在著一系列難以應(yīng)對的需求:
1.這些文檔的數(shù)量、類型及內(nèi)容經(jīng)常改變。
2.該系統(tǒng)必須同時處理新舊兩種文檔類型。
3.這些文檔有時含有多信息文本(rich text),包括Html標記。
4.數(shù)據(jù)是在多個不同位置輸入的,所以我需要信息域幫助解決數(shù)據(jù)分布問題。
5.將來系統(tǒng)遲早要支持數(shù)字簽名。
設(shè)計要點
即使該系統(tǒng)處理的文檔類型會隨時間變化,我仍然希望能夠在存儲XML文檔時對它們進行驗證。因此,每一種文檔類型都需要對定義它的相應(yīng)XML模式進行注冊。
使用Oracle9i XML DB可以將XML文檔分解成關(guān)系對象(結(jié)構(gòu)化存儲)或者只是將這些文檔整個存儲為CLOB(非結(jié)構(gòu)化存儲)。兩種方法都利用了原生的XMLType服務(wù)器類型,從而支持XPath表達式與訪問方法。
因為該系統(tǒng)必須能夠適應(yīng)新的文檔類型而不需改變代碼,所以文檔將存儲為CLOB。
但只存儲XML文檔自身是不夠的。處理文檔驗證的代碼庫以及系統(tǒng)的持久性、同步和治理取決于某些其他數(shù)據(jù)元素,如全局主要害字、日期/時間標記、最初位置及正在處理的文檔類型。這些元素,即文檔屬性,必須與在不同位置間發(fā)送的XML文檔共存,所以需要一個屬性模式來包含它們。
有兩種方法可以將XML文檔同文檔屬性關(guān)聯(lián)起來。一種是簡單地將文檔屬性元素包含在各個文檔模式之中。這種方法提供了一種相當扁平的結(jié)構(gòu),它使XPath表達式較短,但我卻不能處理別人創(chuàng)建的模式。另一種方法是將XML文檔包裝在另一個含有所需屬性的XML文檔中。這種方法需要分別驗證包裝文檔和內(nèi)容文檔,但它會提供所需要的靈活性。
創(chuàng)建XML模式
我的工作將從創(chuàng)建既能表示包裝文檔又能表示內(nèi)容文檔的XML模式開始。
首先從包裝文檔開始,創(chuàng)建一個XML模式,它包含所需的全部文檔屬性和一個用于內(nèi)容文檔的占位符(利用任一元素類型)。所有的文檔屬性都根據(jù)"屬性"元素進行分組。我可以用KeyName元素為文檔命名以便檢索,Schema和Element元素指示Content元素中所包含的文檔類型。
通過Oracle9i XML DB,可以使用一組特定的模式注釋對設(shè)置內(nèi)部存儲的方式進行定制。我可以指定每個元素的存儲類型,為所創(chuàng)建的表和類型提供數(shù)據(jù)庫名。
在這樣的情況下,我想混合使用結(jié)構(gòu)化的XML文檔存儲與非結(jié)構(gòu)化的XML文檔存儲,將內(nèi)容存儲為原生XML,將文檔屬性存儲為對象關(guān)系類型。我將為DOCUMENTS設(shè)定defTable屬性,并給出各PRoperties元素的SQLName值。對于Content元素,我打算將存儲類型設(shè)為CLOB,它表示非結(jié)構(gòu)化的XML存儲。當此模式向數(shù)據(jù)庫注冊時,XML DB將依照模式注釋創(chuàng)建對象關(guān)系類型。
接下來,為了驗證置于Content元素中的文檔的各個類型,還需要為各個文檔類型預(yù)備一個XML模式。
我想跟蹤該系統(tǒng)所能處理的所有內(nèi)容類型,所以我會創(chuàng)建一個存儲程序來注冊內(nèi)容模式。該程序會記錄內(nèi)容類型名和TYPES表中的其他細節(jié),然后向XML DB注冊該模式。因為我在上一步中已經(jīng)為這些文檔創(chuàng)建了CLOB存儲,所以當我使用該程序為內(nèi)容注冊任何一種模式時,該程序都會告訴XML DB不要創(chuàng)建任何新表或?qū)ο箢愋停?br />
Dbms_xmlschema.registerSchema(
schemaURL => schema_url,
schemaDoc => schema,
local => true,
genTypes => false,
genTables => false)
插入數(shù)據(jù)
現(xiàn)在我將插入一個新文檔。
為了更輕松,我要創(chuàng)建一個存儲程序,它將1)檢查文檔內(nèi)容是否已注冊,2)驗證文檔,3)用一般XML包裝文件包裝文檔,并填充屬性元素,4)將文檔插入數(shù)據(jù)庫。要插入一個新文檔,只需要像下面這樣調(diào)用該程序:
dtx_doc.save(xmltype(
getDocument('incident1.xml')),
'Incident-001')
getDocument()調(diào)用是一個實用程序,它基于Oracle9i XML數(shù)據(jù)庫開發(fā)人員指南附錄G中的示例代碼。它作為一個CLOB從文件系統(tǒng)載入文檔。第二個參數(shù)save()的代表KeyName元素,將被用于在文檔上建立索引。
一個突出的XML DB特性是能夠在XML-文檔存儲表上創(chuàng)建基于函數(shù)的索引,如下所示:
CREATE INDEX ix_keyname
ON documents d (d.extractValue(
'/Document/Properties/KeyName'));
檢索數(shù)據(jù)
現(xiàn)在可以對DOCUMENTS表運行基于XPath的查詢,但假如創(chuàng)建一個XML文檔存儲的關(guān)系視圖,如清單 1所示,就能通過標準SQL來訪問結(jié)構(gòu)化的存儲,那么查詢就會更輕易。這樣也可以更輕松地查詢文檔屬性。
現(xiàn)在可以直接查詢該視圖,以查看文檔屬性。
清單 2 中的Print_table()過程是Tom Kyte(asktom.oracle.com)編寫的一個實用程序,它可對查詢進行縱向格式化。 它與本專欄的示例代碼一起放在了網(wǎng)上。
除了通過SQL調(diào)用檢索數(shù)據(jù)外,也可以利用內(nèi)建于該數(shù)據(jù)庫中的Oracle XML DB HTTP協(xié)議服務(wù)器檢索文檔。假如你的數(shù)據(jù)庫監(jiān)聽程序正在運行,你可以在瀏覽器中輸入以下URL,以查看插入文檔的完整XML:
http://localhost:8080/oradb/
DTXDOCS/DOCUMENTS
DTXDOCS是我的數(shù)據(jù)庫用戶名。我也可以在URL中置入一個XPath查詢,并指定一個XML樣式表,它會把XML轉(zhuǎn)換為格式美麗的HTML文檔:
http://localhost:8080/oradb/DTXDOCS/
DOCUMENTS/ROW/Document
[Properties/Subject='Incident-001']
?transform=/public/dtxdocs/incident.xslt
&contenttype=text/html
示例代碼
在DevTrends網(wǎng)站上,我已經(jīng)放置了用于說明本文簡述概念的示例代碼。
其中的說明腳本會告訴你我創(chuàng)建用于應(yīng)用程序的內(nèi)部工作的單一代碼庫以及根據(jù)需要向系統(tǒng)注冊新文檔類型的方法。由于我在實際文檔中沒有使用結(jié)構(gòu)化的存儲,所以這種方法也可能多少會有助于解決模式發(fā)展的問題。
Cameron O'Rourke (cameron.orourke@oracle.com) 擔任Oracle 技術(shù)專家已超個11年。