3.4. 映射次序
本節討論對象-關系映射如何處理次序。
3.4.1. 同級次序, 層次次序, 和文檔次序
同級(sibling)意味著“兄妹”。就是說,同級元素或 pcdata 是有相同父元素的元素或 pcdata。換句話說,它們出現在同一個內容模型中。例如,如果在前面的章節中文檔被表示為一棵樹,這很容易的顯示出那些元素是同級的: 這些元素在這個層次的第二級上,都有 a 作為它們的父元素。
a
___________________________|______________________
| | | | | | | | |
this text c makes b no sense c except as b an example
| | | |
cc bbbb cccc bb
注意在第這個層次的第三級的元素不是同級的,因為它們不共享相同的父元素。這還指出了同級次序,它是在它們的父元素中子元素出現的次序,和層次次序,它是子元素在表示文檔的樹中出現在的級別,二者之間的不同。不同的還有文檔次序,它是元素和文本在一個 xml 文檔中出現的次序。例如:
同級次序(只有一個同級元素的地方次序不顯示):
a
___________________________|______________________
| | | | | | | | |
this text c makes b no sense c except as b an example
1 2 3 4 5 6 7 8 9
| | | |
cc bbbb cccc bb
層次次序:
1 a
___________________________|______________________
| | | | | | | | |
2 this text c makes b no sense c except as b an example
| | | |
3 cc bbbb cccc bb
文檔次序:
a
1
___________________________|______________________
| | | | | | | | |
this text c makes b no sense c except as b an example
2 3 5 6 8 9 11 12 14
| | | |
cc bbbb cccc bb
4 7 10 13
依據 xml 規定,同級次序是重要的。實際上,這依賴于應用。例如,在以數據為中心的應用中,使用 xml 文檔來傳載一個對象或表,同級次序通常是無關緊要的,因為面向對象語言沒有在類屬性之間的次序的概念。類似的,關系數據庫沒有在列之間的次序的概念。所以,同級次序在下列文檔中不是重要的:
<part>
<number>123</number>
<desc>turkey wrench</desc>
<price>10.95</price>
</part>
<part>
<price>10.95</price>
<desc>turkey wrench</desc>
<number>123</number>
</part>
它們都被映射成下列對象和表中的行:
對象 表
========================= ===================================
table parts
object part { -------------------------------
number = 123 ==> number desc price
desc = "turkey wrench" ------ ------------- -----
price = 10.95 123 turkey wrench 10.95
(對此的一個主要的例外是在以數據為中心的文檔必須匹配一個特定的 dtd 的時候。這在一個應用必須驗證文檔的時候發生,比如在它們來自未知或不被信任的來源的時候。盡管在這種情況下 xml schemas 的“all 組”通過允許一組子元素以任何次序出現能幫上忙,但它們不支持重復子元素。)
在另一方面,在以文檔為中心的應用中,通常文檔是為了人的消費而設計的,同級次序是非常重要的。例如,我很可能喜歡第一個評述而不是第二個:
<review>
<p>ronald bourret 是一個
<b>優秀的作家</b>。
只有<b>傻瓜</b>
才不去讀他的作品。</p>
</review>
<review>
<p>ronald bourret 是一個
<b>傻瓜</b>。只有
<b>優秀的作家</b>
才不去讀他的作品。</p>
</review>
對象-關系映射可以保留同級次序,下面將會見到,盡管實際上很少有產品支持它。通過把到簡單元素類型的引用映射到在表中的列,和把到復雜元素類型的引用映射成主鍵、外鍵聯系,它本能的保留層次次序。在保留了層次次序和同級次序的時候就保留了文檔次序。
3.4.2. 映射同級次序
因為面向對象語言沒有類屬性之間次序的概念,而關系數據庫沒有列之間次序的概念,必須與數據值獨立的存儲同級次序值。這么做的一種方式是介入在其中存儲次序值的獨立類屬性和列。這么做的另一種方式在映射自身中存儲次序值。
3.4.2.1. 次序屬性和列
使用次序類屬性和次序列來存儲次序值。它們對立于數據類屬性和數據列。對認定次序很重要的每個被引用的元素類型或 pcdata 都需要一個類屬性或列。例如,考慮上面的混合內容的例子。下面把在 dtd 中的同級次序映射到次序類屬性:
dtd 類
=============================== ========================
class a {
string[] pcdata;
int[] pcdataorder;
<!element a (#pcdata | b | c)*> string[] b;
<!element b (#pcdata)> ==> int[] border;
<!element c (#pcdata)> string[] c;
int[] corder;
}
并接著映射到次序列:
類 表
======================== ========================================
table pcdata
class a { -----column a_fk
string[] pcdata; / column pcdata
int[] pcdataorder; / column pcdataorder
string[] b; table a / table b
int[] border; ==> column a_pk--------column a_fk
string[] c; / column b
int[] corder; / column border
} / table c
/----column a_fk
column c
column corder
注意在標中存儲的次序類屬性與它們定序的類屬性是并列的。
下面的例子展示使用次序屬性來保留在"makes-no-sense"例子中的同級次序。這里要注意的重要的事情是所有次序類屬性共享相同的次序空間。出現在一個次序類屬性中一個次序值不會出現在另一個次序類屬性中。
類 表
================================= =====================================
table pcdata
a_fk pcdata pcdataorder
---- ----------- -----------
1 this text 1
object a { 1 makes 3
pcdata = {"this text ", 1 no sense 5
" makes ", 1 except as 7
" no sense ", table a 1 an example. 9
" except as", a_pk
" an example."} ==> ---- table b
pcdataorder = {1, 3, 5, 7, 9} 1 a_fk b border
b = {"bbbb", "bb"} ---- ---- ------
border = {4, 8} 1 bbbb 4
c = {"cc", "cccc"} 1 bb 8
corder = {2, 6}
} table c
a_fk c corder
---- ---- ------
1 cc 2
1 cccc 6
盡管次序類屬性最常用來維護在混合內容中的次序,它們也可以與元素內容一起使用。例如,考慮下面的元素類型定義。因為在 a 中 b 可以出現任意次,它被存儲在獨立的屬性表中。沒有次序類屬性,將無法確定如何定序 b 子元素。(注意這里不能使用行次序,因為關系數據庫不保證以任何特定的次序返回行。)
<!element a (b*, c)>
3.4.2.2. 在映射中存儲次序
在許多情況下,同級次序只在驗證的時候是重要的;除了必須能驗證一個文檔之外,應用自身不關心同級次序。特別是在以數據為中心的文檔中元素內容。在這種情況下,在映射自身中存儲次序信息就足夠了。
例如,給出下列內容模型,映射可以存儲 a 的子元素的次序是 b 然后 c 然后 d 的信息:
<!element a (b, c, d)>
特別是,限制為在映射中存儲次序信息。例如,考慮下面的內容模型:
<!element a (b?, c, b)>
構造匹配這個內容模型的文檔要求軟件首先決定能獲得多少數據來構造 b 元素。如果只有構造一個 b 元素的足夠數據,它不能第一個 b 元素,因為第二個 b 元素是必須的。
讓多數軟件這么麻煩的這么做是不大可能的。轉而,只對組織所有相同元素類型的同級元素在一起的那些內容模型提供合理的限制。對于許多以數據為中心的內容模型這是足夠的,并可以通過在映射中存儲每個元素在內容模型中的位置來實現。
例如,在下列元素中同級元素的次序可以被如此映射。注意在第三個內容模型中,author 和 editor 二者都可以被賦予相同的次序值或不同的值;如果它們被賦予不同的值,一種類型的所有元素都都會出現在其他類型的任何元素的前面。
<!element part (number, description, price)>
<!element order (number, custnum, date, item*)>
<!element book (title, (author | editor)+, price, review*)>
當次序信息只存儲在映射中的時候,只要內容模型包含多于一個相同類型的元素,文檔的無損流通(round-tripping)就是不可能的。例如,考慮下面的內容模型:
<!element a (b+, c)>
盡管映射可以告訴軟件所有 b 元素必須出現在 c 元素起前面,它不能指定 b 元素的次序。所以,如果數據從包含這種內容模型的文檔傳輸到數據庫然后再傳輸回來,就不能保證 b 元素按原始文檔中的次序出現。幸運的是,對以數據為中心的文檔這通常不是問題。
3.5. 映射屬性
如同前面所見到的,把屬性映射為標量類屬性。本節將討論這種映射的詳情,還有其他一些要點。
3.5.1. 映射單值和多值屬性
有兩種不同的屬性: 單值(cdata、id、idref、nmtoken、entity、notation 和枚舉)和多值(idrefs、 nmtokens 和 entities)。預期的可能是,把它們映射成單值類屬性(接者是列)和多值類屬性(接著是屬性表)。例如:
dtd 類 表
============================ ============ ===========
<!element a (b, c)> class a { table a
<!attlist a string b; column b
d cdata #required> ==> string c; ==> column c
<!element b (#pcdata)> string d; column d
<!element c (#pcdata)> }
和:
dtd 類 表
======================== ============== ==============
<!element a (b, c)> class a { table a
<!attlist a string b; column a_pk
d idrefs #implied> ==> string c; ==> column b
<!element b (#pcdata)> string[] d; column c
<!element c (#pcdata)> } table d
column a_fk
column d
依據 xml 信息集屬性出現的次序是不重要的。例如,下列兩個 xml 被認為是等同的。故此,不需要次序類屬性來維護屬性出現的次序,盡管這么做是完全可能的。
<a b="bbb"
c="ccc"
d="ddd"/>
<a c="ccc"
b="bbb"
d="ddd"/>
在另一方面,值出現在多值屬性中的次序被認為是重要的。這同于同級元素和 pcdata 的情況,可以使用次序類屬性來維護關于在多值屬性中值出現次序的信息。但是,在用于同級元素和 pcdata 的次序類屬性、和用于多值屬性的次序類屬性之間有一個重要的區別: 用于多值屬性的每個次序類屬性都有它自己的次序空間。這可以在下面的例子中見到:
xml 對象
=============== =========================
object a {
<a b="dd ee ff" b = {"dd", "ee", "ff"}
c="gg hh"/> ==> border = {1, 2, 3}
c = {"gg", "hh"}
corder = {1, 2}
}
提醒讀者注意次序類屬性在對象級別不是嚴格必須的;可以用數組次序替代。但是,在關系數據庫中是必須的,因為這里沒有行次序的概念。
3.5.2. 映射 id/idref(s) 屬性
id 屬性用來唯一的標識在 xml 文檔中的元素。使用 idref 和 idrefs 屬性,通過提及后面的元素的 id 來把一個元素與另一個元素關聯起來。通常在不能通過把一個元素嵌套在另一個元素之中來形成這種關聯的時候這么做。例如,考慮下面的有向圖:
a
/ /
b c
/ /
d
它可以在 xml 文檔中表示為:
<a>
<b ref_d="1">
...
</b>
<c ref_d="1">
...
</c>
<d id="1">
...
</d>
</a>
id/idref(s) 屬性映射為主鍵、外鍵聯系。例如,上面的文檔可以在數據庫中存儲為下列表和列:
table a
column a_pk
...
/ /
/ /
table b table c
column a_fk column a_fk
column ref_d column ref_d
... ...
/ /
/ /
table d
column a_fk
column id
...
在數據庫中存儲 id/idref(s) 屬性的時候,數據傳輸軟件需要小心的一件事是 id 只保證在一個給定的 xml 文檔內是唯一的。所以,如果來自多于一個文檔的數據存儲在相同的表中,則不能保證 id 是唯一的。這個問題的解決是以某種方式“修飾” id。可以通過把屬性映射成兩列,一列包含對于每個文檔是唯一的一個值,另一列包含 id,或者修飾 id 自身,比如用加以唯一值的前綴來完成。
在數據從數據庫傳輸到 xml 文檔的時候存在類似的問題。如果取回的數據起源于多于一個文檔,則數據傳輸軟件需要確保 id 值是唯一的。這可能涉及到改變一個或多個值,連同引用它們的所有 idref(s) 屬性的值。
目前,多數產品不把 id/idref 作為有別于其他屬性的屬性來支持。
3.5.3. 映射注記屬性
在 xml 文檔中使用注記(notation)來提醒應用如何處理一個元素或未分析的實體。例如,下列的 "xhtml" 注記可以告訴應用這個元素包含 xhtml 并應當使用瀏覽器來顯示:
<desc type="xhtml">
<html>
<head><title>turkey wrench</title></title></head>
<body>
<p>a very <b>big</b> turkey wrench.</p>
</body>
</html>
</desc>
注記屬性和它們的值對于對象-關系映射通常沒有什么意義;把它們作為簡單的另一種屬性來對待。
對此的唯一的例外發生在注記指示包含的文本的數據類型的時候。例如,注記“base64”可以告訴應用包含二進制數據的一個元素被編碼為 base64 (映射二進制數據到 us-ascii 的一個子集的一種 mime 編碼)。在多數情況下,這種信息只對生成映射的軟件有意義。它可以使用這種信息來映射元素類型到二進制值類屬性并接著到 blob (二進制大對象)。在這些情況下,映射自身不使用這些信息。從元素到到 blob 的映射獨立于注記包含數據類型信息的事實。
對此的唯一的例外是當數據傳輸軟件復雜到基于注記值來在運行時間切換映射的時候。在這種情況下,每種可能的注記被映射成一種數據類型,接著使用它來轉換數據。
3.5.4. 映射 entity/entities 屬性
使用 entity 和 entities 屬性把未分析的、外部數據(比如一個二進制文件)與 xml 文檔關聯起來。映射它們同任何其他屬性一樣,不同的是,在傳輸數據的時候,用實體替換屬性值(在從 xml 傳輸數據到數據庫的時候),或者可以建立一個新實體并把它的標示符存儲為屬性值(在從數據庫傳輸數據到 xml 的時候)。因為未分析實體值可以動態生成,映射指定在數據庫中存儲值還是實體 uri 是個好主意。
因為未分析實體總是有相關的注記,在決定實體的數據類型(在映射時間或運行時間)的時候可能用到這些注記。
3.6. 可供選擇的映射
在前面的章節中,我們已經描述了如何映射 dtd 到數據庫。實際上,這些描述是不完整的,因為還有一些其他方式來完成映射。在本節中,我們將討論兩種最重要的替代者。
3.6.1. 映射復雜元素類型到標量類型
盡管復雜元素類型通常映射成類并接著映射成表,也可能把它們映射成標量類型。換句話說,到復雜類型的引用可以被映射成標量類屬性。這種類屬性的值一般是元素內容,串行化為 xml。在元素的值之作為整體才有意義并且不應該分解為更小的部分的時候這是有用的。
例如,考慮給出關于 part 的信息的一個 xml 文檔。如果某個子元素被部分的用 xhtml 描述,進一步分解它可能沒有意義。如同我們已經描述的那樣,這將導致數據被分散到許多表中;italic 字一個表,bold 字一個表,用在 hyperlink 中的字一個表,等等。所以,最好在一個單一列中存儲這些描述:
dtd 類 表
=========================== =============== ==============
<!element part (num, desc)> class part { table part
<!element number (#pcdata)> ==> string num; ==> column num
<!-- use inline entity string desc; column desc
from xhtml --> }
<!element desc (%inline;)>
例如,下面的描述將如此存儲:
<part>
<number>127</number> table part
<desc> num desc
a very <b>big</b> => --- ----------------
turkey wrench. 127 a very <b>big</b>
</desc> turkey wrench.
</part>
注意存儲數據為 xml 確實導致數據傳輸軟件的問題。特別是,軟件不能區別標記和數據。例如,應用如何決定在下列文本中的 <b> 是一個 <b> 元素還是文本?
an example of the <b> element is <b>this element</b>.
對此的一個解決方法是在數據庫中使用標簽存儲實際元素,和使用實體引用來存儲字符:
an example of the element is <b>this element</b>.
這么做的問題是非 xml 應用不能按它們希望的那樣查找數據庫。
3.6.2. 映射標量類屬性到屬性表
盡管單值的、標量值類屬性通常映射成列,它們也可以被映射成屬性表。這是有用的,例如,在獨立于主要表的一個表中存儲 blob 或不經常使用的類屬性。例如:
類 表
=============== ==================
class part { table parts
string num; ==> column num
string desc;
table descriptions
} column num
column desc
3.7. 結論
對象-關系映射處理所有 xml 文檔,有效的映射到對象,并允許非 xml 應用使用在數據庫中的數據。故此,對于以數據為中心的文檔是個好主意并且(不奇怪的)在某些中間件、多數啟用 xml 的數據庫、和多數啟用 xml 的對象服務器中用作底層模型。
應當注意所有這些產品實現了對象-關系映射輕微不同的版本,并且沒有一個實現了映射中所有可能的東西。在映射的更加公用的部分中,都把復雜元素映射成類并把到元素類型的引用映射成類屬性,同樣的使用主鍵、外鍵對來連接表。但是,一些只對唯 pcdata 元素映射列,另一些只對屬性映射列,還有其他一些允許二者。類似的,多數這些產品不支持同級次序或混合內容,并且許多在映射期間都不允許用戶改變名字。
對象-關系映射對于普通文檔不是個好的選擇。首先,在使用混合內容的時候它是低效的。其次,象基于表的映射一樣,它不保留物理結構、注釋和處理指令。
4. 生成模式
我們現在考慮如何依據對象-關系映射從 dtd 生成關系數據庫模式和反之。因為通過對象-關系映射有很多可能的路徑,這里的算法在每次選擇時簡單的選擇最經常使用分支。例如,可以把到唯 pcdata 元素的單一引用映射成一列或一個單獨的屬性表。因為最通用的選擇是把它們映射一個列,下面的算法從這樣的引用生成一列。
對于面向對象數據庫,生成過程是類似的。
4.1. 從 dtd 生成關系數據庫模式
通過通讀 dtd 并處理每個元素類型來生成關系模式:
復雜元素類型生成帶有主鍵列的類表。
除了在處理內容模型的時候之外忽略簡單元素類型。
要處理一個類型模型:
到簡單元素類型的單一引用生成列;如果這個引用是可選的(? 操作符),這個列是有空值的。
到簡單元素類型的重復引用生成帶有外鍵的屬性表。
到復雜元素類型的引用生成在遠端(remote)類表中的外鍵。
在混合內容中的 pcdata 生成帶有一個外鍵的屬性表。
對所有被引用的元素類型和 pcdata 隨意的生成有次序的列。
要處理屬性:
單值屬性生成列;如果屬性是可選的,這個列是有空值的。
多值屬性生成帶有外鍵的屬性表。
如果一個屬性有缺省值,則把它用作列缺省值。
下面的例子展示了這個過程是如何工作的。考慮下列 dtd:
dtd 表
================================================= =================
<!element order (ordernum, date, custnum, item*)>
<!element ordernum (#pcdata)>
<!element date (#pcdata)>
<!element custnum (#pcdata)>
<!element item (itemnum, quantity, part)>
<!element itemnum (#pcdata)>
<!element quantity (#pcdata)>
<!element part (partnum, price)>
<!element partnum (#pcdata)>
<!element price (#pcdata)>
在第一步,我們為復雜元素類型生成表和這些表的主鍵:
dtd 表
================================================= =================
<!element order (ordernum, date, custnum, item*)> ==> table order
<!element ordernum (#pcdata)> column orderpk
<!element date (#pcdata)>
<!element custnum (#pcdata)>
<!element item (itemnum, quantity, part)> ==> table item
<!element itemnum (#pcdata)> column itempk
<!element quantity (#pcdata)>
<!element part (partnum, price)> ==> table part
<!element partnum (#pcdata)> column partpk
<!element price (#pcdata)>
在第二步,我們為到簡單元素類型的引用生成列:
dtd 表
================================================= =================
<!element order (ordernum, date, custnum, item*)> ==> table order
<!element ordernum (#pcdata)> column orderpk
<!element date (#pcdata)> column ordernum
<!element custnum (#pcdata)> column date
column custnum
<!element item (itemnum, quantity, part)> ==> table item
<!element itemnum (#pcdata)> column itempk
<!element quantity (#pcdata)> column itemnum
column quantity
<!element part (partnum, price)> ==> table part
<!element partnum (#pcdata)> column partpk
<!element price (#pcdata)> column partnum
column price
在最后一步,我們為到復雜元素類型的引用生成外鍵:
dtd 表
================================================= =================
<!element order (ordernum, date, custnum, item*)> ==> table order
<!element ordernum (#pcdata)> column orderpk
<!element date (#pcdata)> column ordernum
<!element custnum (#pcdata)> column date
column custnum
<!element item (itemnum, quantity, part)> ==> table item
<!element itemnum (#pcdata)> column itempk
<!element quantity (#pcdata)> column itemnum
column quantity
column orderfk
<!element part (partnum, price)> ==> table part
<!element partnum (#pcdata)> column partpk
<!element price (#pcdata)> column partnum
column price
column partfk
生成的模式將不會同人工寫的模式一樣。除了命名問題(例如,一個人可能把表叫做 orders、items, and parts),生成算法不能確定在 items 和 parts 直接的聯系是多對一的。這個算法還不能識別 ordernum 和 partnum 可以用作主鍵,并且它不能決定數據類型和列長度,而 xml schemas 解決了后者問題。盡管沒有命名沖突發生或非法名字生成,但二者都是可能的。
4.2. 從數據庫模式生成 dtd
生成 dtd 從一個單一的“根”表或一組根表并處理每個根表開始:
每個根表生成帶有一個單一序列形式的元素內容的一個元素類型。
在表中的每個數據(非鍵)列生成帶有唯 pcdata 內容的一個元素類型和在序列中的一個引用;有空值的列生成可選的引用。
主鍵和外鍵生成如下:
遠端表用同根表相同的方式處理。
把到遠端表的元素類型的引用增加到序列中。
如果鍵是主鍵,則引用是可選的和重復的(* 操作符)。這是因為不能保證在外鍵表中有一行存在,也不能擔保只有一行存在。
如果鍵是主鍵,為在這鍵中的每個列隨意的生成唯 pcdata 的元素類型。如果生成了它們,向序列添加到這些元素類型的引用。這只在主鍵包含數據時是有用的。
如果鍵是外鍵并且是有空值的,引用是可選的(? 操作符)。
在這個處理期間,用來到達表的鍵(如果有的話)是不處理的。這避免了算法重復建立那些在父表中建立了的元素類型。
下列例子展示這個處理是如何工作的。考慮下列數據庫模式:
table orders
column ordernum
column date
column custnum
table items
column ordernum
column itemnum
column quantity
column partnum
table parts
column partnum
column price
在第一步,我們為根表(orders)生成一個元素類型:
表 dtd
================== ===================================================
table orders ==> <!element orders ()>
column ordernum
column date
column custnum
table items
column ordernum
column itemnum
column quantity
column partnum
table parts
column partnum
column price
接著,我們為數據列(date 和 custnum)生成唯 pcdata 元素,并在 orders 元素的內容模型中添加到這些元素的引用:
表 dtd
================== ===================================================
table orders ==> <!element orders (date, custnum)>
column ordernum
column date <!element date (#pcdata)>
column custnum <!element custnum (#pcdata)>
table items
column ordernum
column itemnum
column quantity
column partnum
table parts
column partnum
column price
現在我們為主鍵(ordernum)生成一個唯 pcdata 元素并向內容模型添加到它的一個引用:
表 dtd
================== ===================================================
table orders ==> <!element orders (date, custnum, ordernum)>
column ordernum <!element ordernum (#pcdata)>
column date <!element date (#pcdata)>
column custnum <!element custnum (#pcdata)>
table items
column ordernum
column itemnum
column quantity
column partnum
table parts
column partnum
column price
接著為主鍵被導出到其中的表(items)增加一個元素類型,同樣在它的內容模型中增加到它的一個引用:
表 dtd
================== ===================================================
table orders <!element orders (date, custnum, ordernum, items*)>
column ordernum <!element ordernum (#pcdata)>
column date <!element date (#pcdata)>
column custnum <!element custnum (#pcdata)>
table items ==> <!element items()>
column ordernum
column itemnum
column quantity
column partnum
table parts
column partnum
column price
我們以相同的方式處理在遠端(items)表中的數據和主鍵列:
表 dtd
================== ===================================================
table orders <!element orders (date, custnum, ordernum, items*)>
column ordernum <!element ordernum (#pcdata)>
column date <!element date (#pcdata)>
column custnum <!element custnum (#pcdata)>
table items ==> <!element items(itemnum, quantity)>
column ordernum
column itemnum <!element itemnum (#pcdata)>
column quantity <!element quantity (#pcdata)>
column partnum
table parts
column partnum
column price
接著為外鍵所對應的表(parts)增加一個元素:
表 dtd
================== ===================================================
table orders <!element orders (date, custnum, ordernum, items*)>
column ordernum <!element ordernum (#pcdata)>
column date <!element date (#pcdata)>
column custnum <!element custnum (#pcdata)>
table items <!element items(itemnum, quantity, parts)>
column ordernum
column itemnum <!element itemnum (#pcdata)>
column quantity <!element quantity (#pcdata)>
column partnum
table parts ==> <!element parts()>
column partnum
column price
最后,我們處理外鍵表(parts):
表 dtd
================== ===================================================
table orders <!element orders (date, custnum, ordernum, items*)>
column ordernum <!element ordernum (#pcdata)>
column date <!element date (#pcdata)>
column custnum <!element custnum (#pcdata)>
table items <!element items (itemnum, quantity, parts)>
column ordernum
column itemnum <!element itemnum (#pcdata)>
column quantity <!element quantity (#pcdata)>
column partnum
table parts ==> <!element parts(partnum, price)>
column partnum <!element partnum (#pcdata)>
column price <!element price (#pcdata)>
同于前面章節的情況,生成的 dtd 不同于人工建立的。盡管這里唯一的問題是有關名字的,這個算法不能識別次序列或屬性表。
5. 映射 xml 模式到數據庫
多數 xml 模式語言可以用對象-關系映射來映射到數據庫。準確的映射依賴于語言。ddml、dcd 和 xml data reduced schemas 可以用幾乎與 dtd 一致的方式來映射。對 w3c schemas、relax、trex 和 sox 的映射表現的更加復雜。我還不清楚 schematron 能否映射。
在 w3c schemas 的情況下,能獲得到對象模式并接著到數據庫模式的一個完整映射。簡單的說,這種把復雜類型映射到類(帶有復雜類型擴展映射成繼承),并把簡單類型映射成標量類型(盡管許多細節丟失了)。“all”組都象無序的序列那樣來對待,而替換(substitution)組象選擇那樣對待。最后,多數同一性約束都被映射成鍵。詳情請參見 http://www.rpbourret.com/xml/schemamap.htm。
6. 有關的話題
關于 xml 和數據庫的更加廣泛的討論請參見:
xml and databases (http://www.rpbourret.com/xml/xmlanddatabases.htm)
關于 xml 數據庫產品的一個適當更新的列表請參見:
xml database products (http://www.rpbourret.com/xml/xmldatabaseprods.htm)