將XML存入關聯式資料庫

來源:互聯網
上載者:User
xml|資料|資料庫 介紹

解決把 XML 有效、自動的轉換出入關聯式資料庫的問題有各種方式。資料庫廠商比如 IBM、Microsoft、Oracle 和 Sybase 已經開發了轉換 XML 到資料庫表中的協助工具輔助。各種解決方案如下。


Oracle XML SQL Utility 把 XML 文件項目建模為一組嵌套的表。通過使用 Oracle 對象資料類型建模套入的元素。"SQL-to-XML"轉換使用被對象資料類型引用的表,和嵌套的元素之間的一到一關聯來構造 XML 文檔。"XML-to-SQL"可能要求資料模型的改進(從關係轉換到對象-關係)或重新構造最初的 XML 文檔。
IBM DB2 XML Extender 允許儲存 XML 文檔為 BLOB 式的對象或分解到一組表中。後者得變換叫做 XML 收集,以 XML 1.0 文法定義。
Microsoft 通過擴充 SQL-92 並介入 OPENXML 行集來解決問題。
Sybase Adaptive Server 介入 ResultSetXml Java 類作為在兩個方向上處理 XML 文檔的基礎。


在這篇文章中,我們將詳細討論這些廠商的解決方案。此後,我們將嘗試回答下列問題:


我們可以調整並簡化問題嗎?
在異構資料庫環境中正確的途徑是什嗎?
我將使用下列詞彙表作為一個例子。


<!-- 簡單類型 -->

<!ELEMENT CURRENCY1 (#PCDATA)>
<!ATTLIST CURRENCY1 e-dtype NMTOKEN #FIXED "string"
e-dsize NMTOKEN #FIXED "3">

<!ELEMENT CURRENCY2 (#PCDATA)>
<!ATTLIST CURRENCY2 e-dtype NMTOKEN #FIXED "string"
e-dsize NMTOKEN #FIXED "3">

<!ELEMENT AMOUNT (#PCDATA)>
<!ATTLIST AMOUNT e-dtype NMTOKEN #FIXED "decimal">

<!ELEMENT SETTLEMENT (#PCDATA)>
<!ATTLIST SETTLEMENT e-dtype NMTOKEN #FIXED "date">

<!ELEMENT BANKCODE (#PCDATA)>
<!ATTLIST BANKCODE e-dtype NMTOKEN #FIXED "string">

<!ELEMENT BANKACCT (#PCDATA)>
<!ATTLIST BANKACCT e-dtype NMTOKEN #FIXED "string">

<!-- 衍生類別型 -->

<!ELEMENT ACCOUNT (BANKCODE, BANKACCT)>

<!ELEMENT FXTRADE (CURRENCY1, CURRENCY2, AMOUNT, SETTLEMENT, ACCOUNT)>






Oracle XML-SQL Utility (XSU)

SQL 到 XML 的映射
Oracle 把對象引用鏈從資料庫轉換到 XML 文檔的階層中。在對象-關聯式資料庫,在表 FXTRADE 中的欄位 ACCOUNT 被建模為類型 AccountType 的一個對象引用:

CREATE TABLE FXTRADE
{
CURRENCY1 CHAR (3),
CURRENCY2 CHAR (3),
AMOUNT NUMERIC (18,2),
SETTLEMENT DATE,
ACCOUNT AccountType // 對象引用
}

CREATE TYPE AccountType as OBJECT
{
BANKCODE VARCHAR (100),
BANKACCT VARCHAR (100)
}


從給定的對象-關聯式模式產生相應的 XML 文檔(使用 "SELECT * FROM FXTRADE")如下

<?xml version="1.0"?>
<ROWSET>
<ROW num="1">
<CURRENCY1>GBP</CURRENCY1>
<CURRENCY2>JPY</CURRENCY2>
<AMOUNT>10000</AMOUNT>
<SETTLEMENT>20010325</SETTLEMENT>
<ACCOUNT>
<BANKCODE>812</BANKCODE>
<BANKACCT>00365888</BANKACCT>
</ACCOUNT>
</ROW>
<!-- additional rows ... -->
</ROWSET>


從資料庫提取 XML
下面的例子取自 Oracle 的 XSU 文檔,帶有 SQL 陳述式的適當替換並使用 Oracle 的純 Java JDBC 薄驅動程式。

首先,建立了 OracleXMLQuery 的一個執行個體,其後,執行一個查詢,並把結果表示為上面的 XML 文檔的形式。類似的,可以提取 XML 文檔到 DOM 的形式;在這種情況下,可以調用 qry.getXMLDOM() 取代 getXMLString()。

import oracle.jdbc.driver.*;
import oracle.xml.sql.query.OracleXMLQuery;
import java.lang.*;
import java.sql.*;

// 測試 XML 文檔產生為 String 的類
class testXMLSQL {

public static void main(String[] args)
{
try {
// 建立串連
Connection conn = getConnection("scott", "tiger");

// 建立查詢類
OracleXMLQuery qry = new OracleXMLQuery(conn,
"SELECT * FROM FXTRADE");

// 得到 XML 字串
String str = qry.getXMLString();

// 列印 XML 輸出
System.out.println("The XML output is:\n" + str);

// 總是關閉查詢來釋放所有資源
qry.close();
} catch(SQLException e) {
System.out.println(e.toString());
}
}

// 得到給定的使用者名稱字和口令的串連
private static Connection getConnection(String username,
String password)
throws SQLException
{
// 註冊 JDBC 驅動程式
DriverManager.registerDriver(new
oracle.jdbc.driver.OracleDriver());

// 建立 OCI8 驅動程式的串連
Connection conn =
DriverManager.getConnection(
"jdbc:oracle:thin:@dlsun489:1521:ORCL",
username, password);

return conn;
}
}


儲存 XML 在資料庫中
在例子中使用 OracleXMLSave 來儲存我們的 XML 文檔到對象關聯式模式中;insertXML 方法進行實際的資料插入。

import java.sql.*;
import oracle.xml.sql.dml.OracleXMLSave;
public class testXMLInsert
{
public static void main(String args[])
throws SQLException
{
Connection conn = getConnection("scott", "tiger");
OracleXMLSave sav = new OracleXMLSave(conn, "scott. FXTRADE");
// Assume that the user passes in this document as 0-arg
sav.insertXML(args[0]);
sav.close();
}

...
}


如果 XML 和在資料庫中的對象-關聯式模式是同步的則一切正常,但是如果不同呢? 在這種情況下你有兩種選擇。

調整對象-關聯式模式 -- 可以構造一個可修改的對象-關係視圖來完成多表修改;或者,作為替代,使用 XSLT,可以把 XML 文檔分解成一組"平坦的"子文檔。XSU 不允許屬性值的儲存;它建議你把屬性轉換成元素。

Oracle XSU 的總結
通過如下對象-關聯式模式構造規則建模 XML 到 SQL 映射: 把每個嵌套的 XML 元素映射在適當的類型的一個對象引用上。映射規則被暗含的嵌入到資料庫模型中。

Java API 由類 OracleXMLQuery 和 OracleXMLSave 組成。




IBM DB2 XML Extender

SQL 到 XML 的映射
IBM 的 XML Extender 為使用 DB2 作為 XML 倉庫提供兩種訪問和儲存方法:


XML 列: 儲存和取回整個 XML 文檔為 DB2 列資料
XML 收集: 把 XML 文檔分解成一組關係表,或從一組關係表合成 XML 文檔。


DTD 儲存在 DTD 倉庫中,叫做 DTD_REF 的一個 DB2 表中;它的模式名字是"db2xml"。在 DTD_REF 表中每個 DTD 都有一個唯一的 ID。在資料庫表和 XML 文檔的結構之間的映射是通過資料訪問定義(DAD)檔案的方式來定義的。DAD 引用一個處理過的文檔 DTD,從而提供在 XML 文檔、它的 DTD 和在資料庫表之上的映射規則之間的橋樑。

下面是一個例子 DAD。

<?xml version="1.0"?>
<!DOCTYPE DAD SYSTEM "dad.dtd">
<DAD>
<dtdid>FXTRADE.DTD</dtdid>
<validation>YES</validation>
<Xcollection>
<prolog>?xml version="1.0"?</prolog>
<doctype>!DOCTYPE FXTRADE FXTRADE.DTD </doctype>
<root_node>
<element_node name="FXTRADE">
<RDB_node>
<table name="FXTRADE"/>
<table name="ACCOUNT" key="ID"/>
<condition>
FXTRADE.ACCOUNT=ACCOUNT.ID
</condition>
</RDB_node>
<element_node name="CURRENCY1">
<text_node>
<RDB_node>
<table name="FXTRADE"/>
<column name="CURRENCY1" type="CHAR(3)"/>
</RDB_node>
</text_node>
</element_node>
<element_node name="CURRENCY2">
<text_node>
<RDB_node>
<table name="FXTRADE"/>
<column name="CURRENCY2" type="CHAR(3)"/>
</RDB_node>
</text_node>
</element_node>
<element_node name="AMOUNT">
<text_node>
<RDB_node>
<table name="FXTRADE"/>
<column name="AMOUNT" type="DECIMAL(18,2)"/>
</RDB_node>
</text_node>
</element_node>
<element_node name="SETTLEMENT">
<text_node>
<RDB_node>
<table name="FXTRADE"/>
<column name="SETTLEMENT" type="DATE"/>
</RDB_node>
</text_node>
</element_node>
<element_node name="ACCOUNT">
<element_node name="BANKCODE">
<text_node>
<RDB_node>
<table name="ACCOUNT"/>
<column name="BANKCODE" type="VARCHAR(100)"/>
</RDB_node>
</text_node>
</element_node>
<element_node name="BANKACCT">
<text_node>
<RDB_node>
<table name="ACCOUNT"/>
<column name="BANKACCT" type="VARCHAR(100)"/>
</RDB_node>
</text_node>
</element_node>
</element_node> <!--end of Account element-->
</element_node> <!-- end of FxTrade element -->
</root_node>
</Xcollection>
</DAD>


DAD 通過使用 element_node 到 RDB_node 關聯來定義在 XML 文檔和關聯式資料庫列之間的映射。頂層的 element_node FXTRADE 被定義為在表 FXTRADE 和 ACCOUNT 之間的串連,帶有在 ACCOUNT 表中的欄位 ID 作為主鍵。子項目 CURRENCY1 被映射到在表 FXTRADE 中的欄位 CURRENCY1 上,以此類推。注意 ACCOUNT 元素不包含任何 RDB_node -- 這是不需要的,原因是在前面已經定義了 ACCOUNT 和 FXTRADE 之間的串連。ACCOUNT、BANCCODE 和 BANKACCT 的子項目分別的定義在 ACCOUNT 表中的對應的列中。原子 XML 元素在 DAD 中標記為 text_node。在上面的例子中,除了 FXTRADE 和 ACCOUNT 之外的所有元素都是原子的。

從資料庫提取 XML
通過預存程序來處理 XML 文檔的合成和分解: 預存程序 dxxGenXML() 從資料庫提取 XML 文檔;預存程序 dxxShredXML() 儲存 XML 文檔到資料庫中。

dxxGenXML() 的主要輸入參數是


DAD: 以 DB2 CLOB 資料類型的形式儲存;
結果表名字: 構造的 XML 文檔被轉寄到這個表。


其他輸入參數指定返回行的最大數目,和 <RDB_node> <condition> 元素摒棄(override)選項。輸出參數包括返回行的實際數目,傳回碼,和返回訊息。

在 "IBM DB2 Universal Database XML Extender Administration and Programming, Version 7" 中的一個 C 程式內、可以找到的預存程序的一個詳盡的例子。

儲存 XML 在資料庫中
把 XML 文檔放入資料庫中是通過預存程序 dxxShredXML() 來完成的。

dxxShredXML() 的輸入參數是


DAD: 以 DB2 CLOB 資料類型的形式儲存;
輸入 XML 文檔: 以 DB2 XMLCLOB 資料類型的形式儲存。


它的輸出參數是一個傳回碼和返回訊息。

總結
XML-SQL 映射規則通過資料訪問定義(DAD)檔案的方式來指定,它是一個 XML 文檔。DB2 XML Extender 管理設施包括為每個持久的 DTD 構造 DAD 檔案的一種手段。

進一步增強將包含新的 XML-SQL 轉換文法,它將使用 XML 轉換語言,是 W3C XSLT 的一個子集。




Microsoft SQL Server 2000

SQL 到 XML 的映射
SQL Server 的 SQL-to-XML 和 XML-to-SQL 映射規則使用不同的文法。在下面的提取和儲存段落中討論映射的詳情。

從資料庫提取 XML
在資料庫列和 XML 元素或屬性之間的映射通過在 SELECT 中的 AS 別名的方式來定義:

<資料庫列> AS [元素名字! 嵌套層級! 屬性名稱字! 指示]

同下面一樣,文檔頂層被賦予層級 1。預設的,映射列資料在屬性值上。可以使用指示"element"來改變這個預設設定。

從資料庫產生 XML 的過程有兩步。

步驟 1。建立到你希望輸出 XML 中的原子項目的 As-別名;別名定義了在元素之間的父/子聯絡。下面的表展示給我們的例子文檔的別名。

FXTRADE /* LEVEL=1 */
CURRENCY1 [FXTRADE!1!CURRENCY1]
CURRENCY2 [FXTRADE!1!CURRENCY2]
AMOUNT [FXTRADE!1!AMOUNT]
SETTLEMENT [FXTRADE!1!SETTLEMENT]
ACCOUNT /* LEVEL=2 */
BANKCODE [ACCOUNT!2!BANKCODE]
BANKACCT [ACCOUNT!2!BANKACCT]


步驟 2。在 SQL 中定義輸出樹結構。通過 SELECT 語句定義樹的每個層級,此後通過 UNION ALL 語句的手段把各個層級組合在一起到樹中。層級-1 SELECT 語句介入在所有層級上的原子項目名字。每個 SELECT 語句介入一個樹層級標記和它的父標記。在結果集中有一個單一記錄對應於樹根,如同在下面的第一個 SELECT 語句中定義的那樣。

SELECT
1 AS Tag,
NULL AS Parent,
NULL AS [FXTRADE!1!CURRENCY1],
NULL AS [FXTRADE!1!CURRENCY2],
NULL AS [FXTRADE!1!AMOUNT],
NULL AS [FXTRADE!1!SETTLEMENT],
NULL AS [ACCOUNT!2!BANKCODE],
NULL AS [ACCOUNT!2!BANKACCT]
FROM
FXTRADE
UNION ALL
SELECT
2,
1,
FXTRADE.CURRENCY1,
FXTRADE.CURRENCY2,
FXTRADE.AMOUNT,
FXTRADE.SETTLEMENT,
ACCOUNT.BANKCODE,
ACCOUNT.BANKACCT
FROM
FXTRADE, ACCOUNT
WHERE
FXTRADE.ACCOUNT = ACCOUNT.ID
ORDER BY [ACCOUNT!2!BANKCODE],
[ACCOUNT!2!BANKACCT]
FOR XML EXPLICIT, ELEMENTS


FOR XML 通過分析在組合的行集中的標記和AS-別名構造 XML 文檔。關鍵字 EXPLICIT 選擇構造 XML 文檔的最靈活的、使用者定義的模式。另一個模式 AUTO 通過應用預設規則構造 XML 文檔。關鍵字 ELEMENTS 在元素層級建模 SQL 列;否則,預設的是在屬性層級建模 SQL 列。

儲存 XML 在資料庫中
使用 OPENXML 儲存 XML 文檔,它是一個新的行集合函式,類似於表或視圖。可以使用 OPENXML 來插入或更新或 SELECT INTO 目標表。OPENXML 簡化的文法展示如下:

OPENXML (<XML 文檔控制代碼>, <路徑 pattern>, <標誌>)
WITH (模式 | 表)
儲存 XML 文檔的過程分三步。


使用預存程序 sp_xml_preparedocument,通過把 XML 文檔編譯成內部 DOM 表示來擷取一個 XML 文檔控制代碼。
通過對模式欄位關聯上原子 XML 元素來構造一個模式。 通過路徑 pattern(絕對基礎路徑)加上相對元素路徑來定義 XML 元素。通過標誌值 2 指示以元素為中心的映射。可以使用現存的表替代一個模式,帶有等價於 XML 名字的欄位名字。
使用預存程序 sp_xml_removedocument 從記憶體中刪除編譯過的 XML 文檔。


在下列例子中展示這些步驟。

DECLARE @idoc int
DECLARE @doc varchar(1000)
SET @doc ='
<FXTRADE>
<CURRENCY1>GBP</CURRENCY1>
<CURRENCY2>JPY</CURRENCY2>
<AMOUNT>10000</AMOUNT>
<SETTLEMENT>20010325</SETTLEMENT>
<ACCOUNT>
<BANKCODE>812</BANKCODE>
<BANKACCT>00365888</BANKACCT>
</ACCOUNT>
</FXTRADE>'
-- 建立 XML 文檔的內部 DOM 表示。
EXEC sp_xml_preparedocument @idoc OUTPUT, @doc
-- 執行使用 OPENXML 行集提供者的一個 SELECT 語句。
SELECT *
FROM OPENXML (@idoc, '/FXTRADE/ACCOUNT', 2)
WITH (
CURRENCY1 CHAR (3), '../@CURRENCY1',
CURRENCY2 CHAR (3), '../@CURRENCY2',
AMOUNT NUMERIC (18,2), '../@AMOUNT',
SETTLEMENT DATETIME, '../@SETTLEMENT',
BANKCODE VARCHAR (100), '@BANKCODE',
BANKACCT VARCHAR (100), '@BANKACCT' )
EXEC sp_xml_removedocument @idoc


總結
對於 Microsoft SQL Server 2000,XML 文檔的提取和存檔不使用對稱的文法。提取通過使用 FOR XML 構造擴充出一個 SELECT-子句。儲存介入一個行集合函式 OPENXML,類比於一個表或視圖。提取映射規則是基於 (a)介入指定樹層級用的標記和 (b) 對錶的欄位關聯上在 XML 文件項目之間的父/子聯絡。儲存把 XML 文檔重構到一個平坦的模式或表中;使用 XPath 標記法定義 "欄位-元素"關聯。




Sybase Adaptive Server

SQL 到 XML 的映射
Sybase 使用一個 XML 文件類型 ResultSet 來描述 XML 文檔中繼資料(元素名字、類型、大小等)和實際的行資料二者。下面摘錄自假定的 FxTradeSet.xml:

<?xml version="1.0"?>
<!DOCTYPE ResultSet SYSTEM "ResultSet.dtd">
<ResultSet>
<ResultSetMetaData>
<ColumnMetaData
...
getColumnLabel="CURRENCY1"
getColumnName="CURRENCY1"
getColumnType="12"
... />
...
</ResultSetMetaData>
<ResultSetData>
<Row>
<Column name="CURRENCY1">GBP</Column>
...
</Row>
</ResultSetData>
</ResultSet>


ResultSet DTD 好像不允許嵌套元素的定義。

從資料庫提取 XML
Java 類 ResultSetXml 有一個構造器,它接受一個 SQL 查詢作為參數,此後 getXmlLText 方法從結果集提取個 XML 文檔:

jcs.xml.resultset.ResultSetXml rsx = new jcs.xml.resultset.ResultSetXml
("Select * from FxTrade", <other parameters>);
FileUtil.string2File ("FxTradeSet.xml", rsx.getXmlText());


儲存 XML 在資料庫中
ResultSetXml 類構造器也接受一個 XML 文檔作為參數。此後方法 toSqlScript 產生 SQL 陳述式的序列來從結果集插入/更新到指定的表。

String xmlString = FileUtil.file2string ("FxTradeSet.xml");
jcs.xml.resultset.ResultSetXml rsx = new jcs.xml.resultset.ResultSetXml
(xmlString);
String sqlString = rsx.toSqlScript ("FxTrade", <other parameters>)


總結
XML 文檔的提取和儲存是本質上對稱的。儲存好像不允許修改多於一個表。提取把 SQL 查詢的結果轉換到有平坦結構的文檔中。




廠商比較

廠商 映射規則 單一表/多個表 轉化的手段 對稱的提取/儲存
Oracle 隱含的;通過構造對象-關聯式模式 多個 指定的 Java 類 對稱,如果 XML 文檔和對象-關聯式模式匹配
IBM 資料訪問定義檔案 多個 指定的預存程序 對稱
Microsoft SQL 擴充;行集合函式 多個表用於提取;單一表用於儲存 通過使用 SQL 構造FOR XML和行集OPENXML 不對稱
Sybase 結果集 DTD 單一表;查詢可以包含多個表 通過使用 Java 類 對稱


廠商間的公用特徵是:


XML 持久性建立在特別的基礎上,就是說,沒有一般性的設施來儲存任意 XML 文檔);如果 XML 文檔使用一個新的文法則需要專門的映射;
儲存經常需要資料處理,比如按照使用的地區來重新格式化數值/日期;可以利用 XSLT 來進行 XML 資料整理。





一種可替代的策略

XML 文檔儲存在資料庫中的任務可以劃分到階段? 首先,儲存 XML 在普通的資料庫結構中而不應用任何映射規則;其次,為後續的處理提供一個架構? 這種方法的好處是對於事實上的任何 XML 文檔有一個通用的採集代理(acquisition agent)。本文的餘下部分只提議這種解決方式。

在這種策略下,XML 文檔儲存為正常的樹結構——原始樹資料——用於進一步的應用處理。進一步資料處理的架構是一組資料庫物件(預存程序),類似於 DOM API,用來通過傳統的 SQL 處理來操縱資料。

使用與全自動方式相反的架構方式的好處有: 資料庫群體(population)通常由分布在"純"應用程式代碼、交易處理、資料庫層(layer)和預存程序之間的應用邏輯來控制的,不必提及一些表可能駐留在遠端資料庫中。

此外,在異構的資料庫環境中,擁有一個統一的工具來對不同的資料庫完成相同的任務有著明顯的好處。

作者的解決方案,ObjectCentric Solutions x-Persistence Utility,實現了這裡討論的策略。

原始樹結構通過如下表來定義。

1) 樹節點定義

CREATE TABLE NodeDef (
nodeID udd_id NOT NULL, // 唯一性節點 id
dimID udd_id NOT NULL, // 樹種類: XML
name udd_name NOT NULL, // 節點名字
value udd_paramvalue NULL, // 節點值
value_type udd_type NULL, // 實值型別
power udd_power NULL, // 節點樹層級
isRoot udd_logical NOT NULL, // 頂層節點標誌
descriptor udd_descriptor NULL, // DOM 節點類型
color udd_color NULL // 非正式資料
)


2) 在節點間的父-子關係

CREATE TABLE NodeLinks (
parentID udd_id NOT NULL, // 父節點
childID udd_id NOT NULL // 子節點
)





用例

儲存 XML 文檔在資料庫中需要調用 XML2SQL 程式:

XML2SQL <XML 文檔檔案名稱>

使用下列預存程序實現從資料庫提取 XML 文檔為一個樹結構:


get_tree_roots <樹種類> -- 提取一個給定森林的所有文檔根 id
get_tree <根 id> -- 提取一個給定根(文檔)的所有節點
get_children <節點, 層級> -- 提取一個給定節點的特定層級的所有子節點


實現細節:


當前的平台包括: Sybase,MS SQL Server。
被評估的平台: Oracle,DB2 和 PostgreSQL。
工具 + 生產力建立在 Xerces XML 分析器頂上。
資料庫安裝涉及到的只是增加一些表,和導航資料庫表為樹結構的預存程序。


x-Persistence Utility 當前在 Open Finance Laboratory 中用作基於 XML 的資料擷取代理的核心,它是如證券管理、負債管理、風險管理等範圍內的財務應用的一個可定製的整合平台。Open Finance Laboratory 接受 FpML 作為用於利率匯出的一個敘述性語言。x-Persistence Utility 目前用作 FpML/FRA 資料擷取代理。



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.