1.0 簡介 本論文簡要的探討了xml和數據庫之間的關系,同時列出一些可以使用數據庫處理xml文檔的軟件。 雖然這里不打算詳盡地介紹這些軟件,但是筆者希望它能夠描述使用數據庫處理xml文檔中的主要部分。這里有點偏向與關系數據庫,因為我的經驗如此。 2.0 xml是數據庫嗎? 在開始討論xml和數據庫之前,我們需要回答一個縈繞在很多心頭的問題: "xml是數據庫嗎?"在嚴格意義上將,如果"xml"是指xml文檔時,答案是"否"。盡管xml文檔包含了數據,但是如果沒有其他的軟件來處理這些數據,它對于數據庫的意義和其他文本文件沒有什么區別。 如果在更為寬泛一些的意義上將,當"xml是指xml文檔以及所有相關的xml的工具和技術時,答案則是"是"。 之所以肯定是由于xml提供了許多數據庫中所需要的部分:存儲(xml文檔),結構(dtd,xml schema語言),查詢語言(xql, xml-ql, quilt等), 編程接口(sax, dom),等等。不過...xml還缺少很多在真實的數據庫中所必備的內容: 有效的存儲、索引、安全、交易、數據完備性、多用戶訪問、觸發、多文檔查詢等。因此如果在數據量一般、用戶較少、性能要求不高的環境下可以把xml當作數據庫來使用;而在大多產品的環境中,要求有許多的用戶使用、需要嚴格的數據完整性并且對性能有很高的要求,xml就不能勝任了。而且,考慮到象dbase和access等數據庫既便宜又十分易用,因此甚至在第一種情況下xml都很少有理由充當數據庫的角色。 3.0 為什么使用數據庫?當在考慮使用xml和數據庫時,第一個要問自己的問題應該是:為什么我需要使用數據庫?你需要將原有的數據導出?你需要保存你的web主頁?你是要在一個電子商務應用中使用數據庫,而且其中xml當做傳輸的數據格式?這些問題的答案都將直接影響到你對數據庫和中間件(如果有的話)的選擇。 例如,假設你在電子商務應用程序中使用xml來進行數據傳輸。這是很好的方案,因為你的數據具有高度規范的結構,而xml中的那些實體和編碼對你而言并不重要了。畢竟樣你關心的僅僅是數據而不在于這些數據如何在文檔中進行物理的存儲。如果你的應用程序相對比較簡單的話,關系數據庫和數據傳輸中間件將可以滿足你的需求;如果應用程序龐大而且復雜,那么你就需要一個完全支持xml的開發環境了。 從另一方面來說,假設你有一個從零散的xml文件創建的網站。你不僅需要管理這個網站,你還要提供方法讓用戶可以查詢其中的內容。這時你的文件將非常的不規范,而實體的使用對你來說將變得很重要,因為這些文件的結構是網站的根本。在這個例子中,你就需要某類"原生xml"數據庫可以執行版本化、跟蹤實體的使用并且支持如xql這樣的查詢語言。 4.0 數據和文檔的對比 筆者認為,在選擇數據庫時,最重要的判斷因素可能是你是利用數據庫來保存數據還是保存文檔。如果你想保存數據,你需要的數據庫主要是面向數據存儲(例如關系型數據庫或者面向對象型數據庫)以及在數據庫和xml文檔之間相互轉換。從另一個角度來將,如果你想存儲文檔,你需要一個專門設計用來存儲文件的內容管理系統。 雖然你可以自己把文件保存在關系數據庫或面向對象數據庫中,可是你常會發現你的工作是在重復內容管理系統的功能。類似的,雖然一個內容管理系統通常是建立在面向對象數據庫或關系數據庫之上,但要是把一個內容管理系統當做數據庫來使用就可能非常的令人困繞。 你需要存儲數據還是文檔,答案常常取決于你的xml文檔。原因是xml文件分為兩大類:以數據為中心和以文檔為中心。. 4.1 以數據為中心的文件 以數據為中心的文件的特點是結構相當規范、數據顆粒度好(也就是說,數據中最小的獨立單元是pcdata元素或者是屬性)、很少或者沒有混合內容。其中同層次元素和pcdata的出現順序并不重要。典型的例子是,xml文檔包含了銷售定單、飛行安排、餐館菜單等等。數據為中心的文檔常被用于機器的使用,這時xml可能是多余的---它僅僅是數據傳輸的手段而已。 例如,下面的銷售定單的文檔就是以數據為中心的: abc industries 123 main st. chicago il 60609 981215 turkey wrench: stainless steel, one-piece construction, lifetime guarantee. 9.95 10 stuffing separator: aluminum, one-year guarantee. 13.27 5 在xml的世界中,許多內容豐富的文檔實際上都是數據為中心的。我們以顯示圖書信息的amazon.com網站為例。雖然這個頁面是相當巨大的文本,但是這個文本的結構是高度規范的,其中許多的部分對任何的書本描述頁面都是相同的,并且特點頁面中的各部分的大小都是有限的。也就是說,該頁面可以通過一個簡單的、數據為中心的xml文檔來建立,其中包含了從數據庫中檢索得到的文本信息以及一個xsl樣式表。通常,目前任何通過在模板中填充數據庫數據而動態構造html頁面的網站都可以被上面介紹的用以數據為中心的xml文檔和一個或者多個的xsl樣式表方式替代。 abc industries agrees to lease the property at 123 main st., chicago, il from xyz properties for a term of not less than timeunit="months">18 at a cost of currency="usd" timeunit="months">1000 可以從下面的xml文檔和簡單的樣式表得到: abc industries 123 main st., chicago, il xyz properties 18 1000 4.2 以文檔為中心的文件 以文檔為中心的文檔的特點是:結構不規范、數據顆粒度更大(即,最小的獨立數據單元是包含有混合內容的元素或者就是整個xml文檔)以及含有大量的混合內容。其中相同層次的元素和pcdata出現順序是非常重要的。典型的例子是書、電子郵件、廣告以及大多數xhtml文檔。以文檔為中心的文檔是用于人的使用。 例如,下面的產品描述文檔就是以文檔為中心: turkey wrench full fabrication labs, inc. like a monkey wrench, but not as big. the turkey wrench, which comes in both right- and left-handed versions (skyhook optional), is made of the finest stainless steel. the readi-grip rubberized handle quickly adapts to your hands, even in the greasiest situations. adjustment is possible through a variety of custom dials. you can: order your own turkey wrench read more about wrenches download the catalog the turkey wrench costs just $19.99 and, if you order now, comes with a hand-crafted shrimp hammer as a bonus gift. 4.3 數據、文檔和數據庫 在現實情況中,以數據為中心的文件和文檔為中心的文件之間的區別并不是很嚴格。例如,一個以數據為中心的文件(如一張發票),也有可能包含粗顆粒度、不規則的數據(如發票的描述部分)。而一個以文檔為中心文件(如用戶手冊)也可能包含有良好顆粒度、規則的結構化數據(通常是元數據),例如作者和修訂日期。除此之外,讓你的文檔具有以數據為中心或者以文檔為中心的特點有助于你判斷是關心數據還是文檔,這也將決定你需要采用什么樣的系統。 要存儲或檢索數據,你可以使用一個數據庫(通常是關系型、面向對象型或者是層次型)和中間件(字帶或者是采用第三方),你也可以使用xml服務器(即創建分布式應用的平臺,例如利用xml進行數據傳輸的電子商務應用)。要保存文檔,你將需要一個內容管理系統或者是一致性的dom實現系統。有關各類系統的探討在5.0 "存儲和檢索數據" 小節和6.0 " href="#storingretrievingdocs">存儲和檢索文檔 " 小節。你也能夠在 href="http://www.rpbourret.com/xml/xmldatabaseprods.htm"> xml數據庫產品 中了解詳細的相關產品列表。 5.0 存儲和檢索數據 在以數據為中心的文檔中的數據內容可能來自數據庫(此時你想把數據導出為xml格式),也可能是xml文檔(此時你想把數據存儲在數據庫中)。前者的例子是在關系型數據庫中存儲的大量現有數據(或稱遺產數據);后者的例子是將數據作為xml發布在web中,而且你想要在你的數據庫中進行存儲以進行更多的處理。如此,根據你的需求,你可能需要將xml文檔轉移到數據庫的軟件,也可能需要從數據庫轉移到xml文檔的軟件,或者兩者都支持。 5.1 轉移數據 將數據存儲在數據庫中時,經常需要丟棄大量與文檔有關的信息,例如文檔名稱和dtd,同時還有其物理結構,例如實體的定義和使用、屬性值和同層元素的順序、二進制數據的存儲方式(是base64編碼、是未析實體或他方式)、字符數據段和其他的編碼信息。類似的,當從數據庫中檢索數據時,生成的xml文檔結果除了非預定義實體lt(<"),gt(">"), amp("&"), apos("’"), quot(""")不包含任何cdata或實體引用。而同層元素和屬性的出現順序也常常就是從數據庫中返回的數據的次序。 盡管一開始有些讓你吃驚,但是這常常是合理的。例如,假設你需要用xml作為數據格式把一張銷售從一個數據庫中轉移到另一個數據庫中。在這種情況下,在xml文檔中并不關心銷售單的編號是保存在銷售單的日期的前面還是后面,也不用關心是否將顧客的名稱保存在字符數據(cdata)段還是作為一個外部實體,或者直接當成一個pcdata。最重要的在于相關的數據是從第一個數據庫轉移到第二個數據庫中。這樣,這個數據傳輸軟件就需要考慮數據的層次結構(該結構將銷售單的有關進行進行了分組),而其他則不必過多考慮。 忽略文檔信息以及其物理結構的后果之一是文檔的"逆反回歸"的不一致效應,即將一個文檔的數據存儲在數據庫中,然后根據這些數據重新組織成新的文檔。而即便是根據標準格式處理,得到的也常常是和前面不同的文檔。這是否可以接受要取決于你的需求,而且也將影響到你對數據庫和數據傳輸中間件的選擇。 5.2 從文檔結構到數據庫結構的映射 為了在xml和數據庫之間傳輸數據,需要在文檔結構和數據庫結構之間進行相互的映射。這樣的映射通常分為兩大類: 模板驅動和模式驅動。 5.2.1 模板驅動的映射 在以模板驅動的映射中,沒有預先定義文檔結構和數據庫結構之間的映射關系 ,而是使用將命令語句內嵌入模板的方法,讓數據傳輸中間件來處理該模板。例如,考慮下面的模板(注意該模板并不適用任何實際的產品),在<selectstmt>元素中內嵌了select語句: <?xml version="1.0"?> <flightinfo> <intro>the following flights have available seats:</intro> <selectstmt>select airline, fltnumber, depart, arrive from flights</selectstmt> <conclude>we hope one of these meets your needs</conclude> </flightinfo> 當數據傳輸中間件處理到該文檔時,每個select語句都將被各自的執行結果所替換,得到下面的xml格式: <?xml version="1.0"?> <flightinfo> <intro>the following flights have available seats:</intro> <flights> <row> <airline>acme</airline> <fltnumber>123</fltnumber> <depart>dec 12, 1998 13:43</depart> <arrive>dec 13, 1998 01:21</arrive> </row> ... </flights> <conclude>we hope one of these meets your needs</conclude> </flightinfo> 這種以模板驅動的映射可以相當的靈活。例如,有些產品可以允許你在任何結果集合中替換你想要的內容(包括在select中使用參數),而不是象上面的例子中簡單地格式化結果。另外它還支持使用編程來進行構造,例如循環和條件判斷結構。還有一些還支持select語句的參數化,例如通過http來傳遞參數。 目前,以模板驅動的映射只支持從一個關系型數據庫轉換成xml文檔的情況。 5.2.2 模型驅動的映射 在以模型驅動的映射中,利用xml文檔結構對應的數據模型顯式或隱式地將映射成數據庫的結構,而且反之亦然。它的缺點是靈活性不夠,但是卻簡單易用,這是因為它是基于具體的數據模型來進行映射的,通常能夠為用戶實現很多地轉換工作。由于將數據從數據庫轉換成xml的結果依照了單個模型, 因此通常在這種方式下通常結合xsl來提供模板驅動的系統中所具有的靈活性。 在xml文檔中的數據視圖通常有兩種模型:表格模型和特定數據對象模型。有時候也可能會出現其他的模型。例如,通過采用id和idref屬性,一個xml文檔可以用來一個指定的圖形。不過,很多現有的中間件并不支持這些模型。 5.2.2.1 表格模型 許多中間件軟件包都采用表格模型在xml和關系型數據庫之間進行轉換。它把xml的模型看成是一個單獨的表格或者是一系列的表格。也就是說,xml的文檔的結構和下面的例子相類似,其中在單個表格的情況下,<database>并不出現: <database> <table> <row> <column1>...</column1> <column2>...</column2> ... </row> ... </table> ... </database> 其中的術語"table"可理解為單個的結果集(當從數據庫向xml中轉換數據時),或者是一個單獨的表格或可更新的視圖(當從xml向數據庫轉換數據時)。如果數據需要來自多個結果集(當數據來自數據庫中時)或者與僅僅表達成一系列表格的集合(當轉換數據到數據庫時)相比,xml的文檔包含有更深層次的嵌套元素,那么類似的轉換幾乎是不可能的。 5.2.2.2 特定數據對象模型 xml文檔中第二種普遍的數據模型是特定數據對象的樹型結構。在該模型中,元素類型通常對應對象,而xml中的內容模型、屬性和pcdata則對應對象的屬性。這種模型直接映射成面向對象的數據庫和層次型數據庫,當然借助于傳統的對象-關系映射技術和sql 3對象視圖也可以映射成關系數據庫。要注意的是,這種模型并不是文檔對象模型(dom)。dom是對文檔本身進行建模,而不是對文檔中的數據。如 href="#writeyourown">6.1.2小節所述,dom用來在關系型數據庫的基礎上建立內容管理系統。 例如,上面的銷售定單文檔就可以看作是由五個類所組成的樹型結構。如下面的視圖所示,包括orders, salesorder, customer, line和part類: orders | salesorder / | customer line line | | part part 當把一個xml文檔建模為一棵特定數據對象樹時,就沒有必要要求元素一定要對應于對象。例如,如果一個元素只包含pcdata,如銷售定單文檔中的custname元素,它可以當作一個屬性進行處理,因此屬性只包含單一的、標量型數值。類似的,有時將混合元素或元素內容模型化成屬性也是非常有用的。一個現成的例子就是在銷售定單文檔中對description元素的處理:盡管它在xhtml的格式中有混合內容,但是將description元素看作單個的屬性會更有用些,因為它的組成部分本身并沒有什么意義。 5.3 數據類型、空值、字符集合和其它 本節將探討一些有關來自數據庫的xml文檔的存儲問題。通常,你決定不了你選擇的中間件是如何解決這些問題的,但是你最好應該意識到這些問題的存在,因為這有助于你正確選擇你的中間件。 5.3.1 數據類型 xml不支持任何有實際意義的數據類型。除了未析實體,所有xml文檔中的數據都被當成文本來對待,即便它能夠用其他的數據類型(如日期或者整數)來表示。通常,數據轉換中間件將把xml文檔中的文本轉換成其它數據庫中的數據類型,反之亦然。然而,特定的數據類型所識別的文本格式是有限制的,例如受到提供的jdbc driver所支持的數據類型的限制。在這些眾多的數據類型中,日期類型通常會導致麻煩。不同國際地區的數字格式的差異也可能產生問題。 5.3.2 二進制數據 通常有兩種方法將二進制數據保存到xml文檔中的:未析實體和base64編碼處理(一種mime編碼方法,可以將二進制數據映射成us-ascii的子集)。 對于關系型數據庫,這兩種方法都可能存在問題,因為從數據庫中保存和檢索二進制數據的規則非常的嚴格,這樣對會導致中間件出現問題。 另外,并沒有一種標準的符號用來說明一個xml文檔中的元素包含有base64編碼數據,從而使得中間件可能根本就不能夠識別這種編碼。最后,在存儲數據到數據庫時,可能會忽略與未析實體或base64編碼元素相關的符號。所以,如果對你而言二進制數據非常重要的話,請務必要確認你的中間件是否支持二進制數據。 5.3.3 空值 在數據庫世界中,空值(null)數據意味著數據不存在值。但是這與一個值為0的數字或長度為0的字符串有很大的區別。例如,假設你的數據來自一個氣象站, 如果氣象站的溫度計出了毛病讀不出溫度值,那么你的數據庫中將存儲一個null值而不是一個0。顯然,值為0完全是另外一回事了 xml中空值概念的支持可以通過設置可選的元素類型或屬性來實現。如果元素類型或屬性值為null,xml只要在文檔不包含該元素或者屬性就可以了。但是對數據庫而言,空的元素或包含0長度字符串的屬性并不是空值null:它們的值為長度為0的字符串。 當在xml文檔和數據庫結構之間相互映射過程中,你必須特別注意那些可選的元素類型或屬性是否對應于數據庫中的空值項。如果不這么做的話,很可能出現插入錯誤(當將數據轉換到數據庫中時)或者無效文檔錯誤(當將數據從數據庫讀出時)。 因為同樣要用符號空值,xml中相對與數據庫而言更為靈活。具體來講,許多xml用戶很可能包含空字符串的空元素或屬性是空值。這個時候你必須考慮如何選擇合適的中間件來解決這個問題。一些中間件可以讓用戶選擇在xml文檔中定義用什么來組成空值。 5.3.4 字符集 根據定義,除了一些控制字符,xml文檔能夠包含任何的unicode字符。但是不幸的是,許多數據庫都限制或則不支持unicode,而且需要一些特殊的配置才能夠處理非ascii編碼的字符數據。如果你的數據包含了非ascii字符,那么務必要核實你的數據庫和中間件是否能夠處理這些字符。 5.3.5 處理指令 處理指令并不屬于xml文檔中的“數據”部分,因此目前許多中間件可能不能正常的處理。問題是,尤其是在將xml文檔結構嚴格映射成數據庫結構時,處理指令通常是很難處理的,因為它們可以虛擬地出現在文檔的任何位置。因此,中間件就很難判斷將它們保存到什么位置以及在什么時候檢索讀取出來。如果處理指令和文檔的循環回復("round-tripping")對你而言是非常重要的話,就務必檢查你的中間件是如解決這個問題的。 5.3.6 存儲標記 在 href="#markup">4 href="#markup">.2.2 小節中提到,有時候將包含元素或者混合內容的元素不作進一步的解析而直接保存到數據庫中是非常有用的。最常見的方法是簡單的把這個標記本身直接保存到數據庫中。不幸的是,當從數據庫中檢索數據時將產生問題:不可能判斷數據庫中的標記到底是真的標記還是代表了標記字符的實體,如由lt和gt轉義的字符。 例如,下面的description元素: <description> <b>confusing example:</b> <foo/> </description> 在數據庫中存儲為: <b>confusing example:</b> <foo/> 這時數據庫就不能判斷<b>和<foo>是標記還是文本。有幾種可能的解決方法,如以一定的方式來標志標記或者對非標記的標記字符使用實體。但是這時你要格外注意這樣的方式是否和使用這些的數據的其它應用兼容。例如,如果你想查詢數據庫中的小于號("<")和 lt實體("<")時就要特別留心。 5.4 從數據庫的結構生成dtd及其互逆過程 在xml文檔和數據庫之間轉換數據時,一個普遍問題是:如何從數據庫的結構(schema)生成xml的dtd,如果從xml的dtd產生數據庫的結構。簡而言之,這是非常直接的操作,但是產生的結果通常離許多用戶的期望值還有一些距離。 (還要注意這通常是一次性操作,而大多數應用,尤其是所有的垂直性應用都結合了已知的dtd和關系型schema的集合。顯而易見的特例是在關系數據庫中存儲隨機xml文檔或者將關系型數據發布為xml文檔的工具;而在后面的情況中,dtd的作用并不明顯。) 對于元素類型中每個有單一數值的屬性和只包含有pcdata內容的子元素類型在該ta ble中新建立一列(字段)。如果子元素類型或則屬性是可選的,讓該字段允許為空。 對于每個有多值的屬性或則多僅含有pcdata內容的子元素類型,再建立一個分開的 table來保存他們的值,通過它們的父表的主關鍵字連接到父表。 對于每個子元素,這些子元素本身還有元素或則混合內容,使用父表中的關鍵字將 父元素表連接到子元素表中。 而下面則是一個從關系數據庫的結構生成xml文檔的過程(簡化過的): 對每個table,新建一個元素。 對表中的每列,建立一個屬性或則只含pcdata的子元素 對每個包含有在主鍵/外鍵關鍵字關系中主鍵值的列,新建一個子元素。 例如,下面的過程(經簡化)說明了如何從一個dtd生成一個關系型結構: 對于每種包含元素或者混合內容的元素類型,新建一個表格和一個主鍵字段。 對于每個包含混合內容的元素類型,創建一個單獨的表格,其中存放未析數據,通過父元素主鍵鏈接到父表格。 對于此元素類型的每個單值屬性和只包含未析數據內容、只出現一次的子元素,在該表格中創建一個字段。如果元素類型或者屬性是可選的,可以讓設置該字段為空值。 對于每個多值屬性和多次出現的子元素,創建一個單獨的表格來存儲數值,并且通過父元素主鍵鏈接到父表格。 對每個有元素或者混合內容的子元素,通過父元素主鍵將父元素表格和子元素表格相連接。 下面的過程(經簡化)說明了如何從一個關系型的結構生成一個dtd: 對于每個表格,新建一個元素; 對于表格中的每個字段,新建一個屬性或者是只包含未析數據的子元素; 對于每個表格字段中提供主鍵的主鍵/外鍵的關系都新建一個子元素。 不幸的是,這些過程還存在著一些缺陷。例如,dtd中沒有方法預先準確地規定數據類型或者字段長度。 因為任何的預先定義(例如通過讀取一個示例文檔)在讀取其它“類型”的文檔或者其他文檔中包含有超過字長內容的文檔時就會產生錯誤。(長久之策是使用xml schema文檔的數據類型。)簡單來說,當從一關系型結構生成dtd時,是沒有辦法預先判斷子元素“應該”出現的順序或者字段(如數據庫內部的行標識)是否該進行完全轉換。 在以上兩種情況中都可能產生命名的沖突。 盡管有這樣那樣的缺陷,但是這些方法仍然能夠很好地奠定在關系型結構和dtd之間互相轉換的起點。中國最大的web開發資源網站及技術社區,