, K: G C/ y8 Z% }" T& F2.0 为什么使用数据库? * F; u1 [6 _! l; F* o
当你考虑到要使用XML和数据库时的第一个要问你自己的问题应该是:为什么我需要使用数据库。你是需要显示数据?你是需要一个保存你主页的空间?数据库在电子商务运用程序中时把XML当做数据传输格式传送吗?这些问题的答案都将直接影响到你对数据库和中间件(如果使用了的话)的选择。 举例说明,假设你是把XML做为一种数据传输3 R* [: s3 F9 x4 Y' T+ _" q
格式使用在你的电子商务运用程序中。 # ]. |6 @. a3 [( F8 D那么意味着你需要传输的数据格式将主要是具有高度规范结构,那么在XML中的那些自己的编码规范对你而言并不重要了,这样你的兴趣就仅仅是在数据上而不是在这些数据如何物理存储在文 档中了。如果你的运用程序关系简单,那么一个关系数据库和数据传输中间件将能够满足你的需求;如果关系庞大和复杂,那么你就需要一个完全支持XML的开发环境了。 : w" X8 @- m0 n t/ ^ A5 S: o* ^
从另一方面来说,假设你是要实现从杂散的XML文件中创建一个网站的功能。你不仅需要管理这个网站,你还要提供给用户查询其中内容的功能。这时你的文件的格式将是高度 & o* O6 x G8 O. F
的不规范,而实体的使用对你来说变得很重要,因为这些文件的结构是网站的基本功能需求。 & B A1 {8 W1 P+ Q& b- G- a4 f' e在这个例子中,你就需要一些"native XML"数据库而不是普通的关系数据库,执行解释 9 u2 f: j- [& B% c1 } E、XML实体使用和支持查询语言(例如XQL)。 ; y! Z! l! G0 Y& R4 s 6 q6 M4 b9 P1 h" a9 e% d9 J& M' |2 t* e7 s* p: b" y# ]
3.0 数据和文档的对比 , Y; n, Y5 w1 a, o# Y, C 也许在大多数情况下,判断是否采用数据库的最重要的因素是你使用数据库是用来 + y1 e. U8 v3 l, v, x0 M保存数据呢还是保存文件。如果你想保存数据, 你需要的数据库则主要是面向数据存储的,例如一 8 f1 r$ N. i5 }) J, X- Y个关系数据库或则一个面向对象的数据库,或则也可以是一个在数据库和XML文档之间传递数据的 & v0 O d: a$ k9 U
中间件。从另一个角度来说,如果你想存储文件,你需要一个专门设计用来存储文件的内容管理 . x9 E. O1 n" w: ^, } k$ e4 e
系统。虽然可以把文件保存在关系数据库或则面向对象的数据库中,但你会发现你的工作 7 e/ M' l2 U/ S1 U- w- e
经常是在重复实现一个内容管理系统中的功能而已。简单说,虽然一个内容管理系统通常是建立 , w' a* Y8 ~. @+ c+ S, M在一个面向对象数据库或则关系数据库的顶层,但是如果只是把一个内容管理系统当做数据库 # o9 k# f% L- l
来使用被证明是失败的。 , c, T( }) @2 D) G, l) O
你是否需要存储数据或则文件经常取决与你的XML文件。原因是XML文件分为两类: : c4 h8 A9 R/ D
数据为主和文档为主。 ) x) [1 O# p* V: ?% y$ O2 y& S * i8 A' c! Z' U5 j% U5 J3.1 数据为主的文件 3 d9 H3 l, l, e6 G% U) q& {: i4 I1 ] 数据为主的文件表现出来的特点是结构相当规范,数据格式良好(就是说,数据中 " b3 J% ^+ b4 O& C+ ^
最小的独立单元是PCDATA-only元素级别或则是一个属性),和一些或则没有混合内容。其中同 & m) Y% a$ G8 _) s9 S7 u8 L; k
类型元素和PCDATA的出现顺序并不重要。例如XML文件内容是销售单、飞行计划、餐馆菜单等等。 3 _, ?" H A( a f9 h2 ]
数据为主的文件经常被用来设计机器消费,这时XML的调用是多余的---它仅仅是一种数 ) P9 O- r& }% E. `9 {据传输。 + G* s: o+ f0 z) E5 m
例如,下面的销售单就是一个数据为主的文档: ! X( j0 T9 r2 t) p
<Orders> 9 v- M3 A0 I6 x2 k
<SalesOrder SONumber="12345"> B# [8 N7 d. {( S
<Customer CustNumber="543"> ) v# b3 w5 B& I
<CustName>ABC Industries</CustName> " d8 h& N! r4 B9 | <Street>123 Main St.</Street> 0 d. K( W0 L% `1 m% ~2 o% m
<City>Chicago</City> 1 B" Y3 j4 s& G, ~, I Z1 P1 l# A) `
<State>IL</State> 6 P5 a, P$ W8 Z2 |4 M5 _ <PostCode>60609</PostCode> S- \5 p( W8 ]$ y8 E
</Customer> ) B1 n' }+ d; S0 W$ T2 r <OrderDate>981215</OrderDate> - K4 G# K2 D! m* g/ f8 q
<Line LineNumber="1"> ) b7 T/ `5 F( [7 \" [) V3 V <Part PartNumber="123"> 9 F0 D( e' v' c1 D <Description> 4 v0 [: \0 `4 s0 D. l7 `, H1 T& L
<p>Turkey wrench:<br /> - _/ o' V3 R, A0 p4 T& \ Stainless steel, one-piece construction, * J6 ]1 l; F. l6 v8 v) G6 ` lifetime guarantee.</p> 6 U b! d# x4 W4 X3 V4 R* z+ U </Description> # e8 b# b2 ]1 N# T8 _ <Price>9.95</Price> 4 f- w9 T9 Q; |1 T3 I: e: p" q! ] </Part> : }- E& L1 h3 s+ m; \" K$ Y <Quantity>10</Quantity> ! i8 ] o- e+ ?3 s$ Y </Line> 0 C& _2 r( d* `, V0 L# } <Line LineNumber="2"> 8 }" u3 i: a' N% i2 X
<Part PartNumber="456"> X# d) }8 w. R8 I& H5 S. J3 \ <Description> 1 v4 {, l- v w' Q$ @" Q7 r% Q
<p>Stuffing separator:<br /> 9 n9 D2 Q+ }# N8 X Aluminum, one-year guarantee.</p> 8 G+ {, A* n: E, M( K5 b
</Description> 2 R' z- O8 F, X+ L6 M* o' z
<Price>13.27</Price> ; n& {* [2 l- ^ </Part> , P N! c7 I5 C* f" [ <Quantity>5</Quantity> $ H4 i* L1 z! A- G! S ]( q3 ^/ w1 M$ P </Line> w8 c0 @( z* d2 m- f7 F% @
</SalesOrder> : |) Q1 r p1 f- D- D. d4 W9 @: r </Orders> j* x8 f# [: Y3 ?5 `
注意在XML世界中,许多(其实应该是大量)的文件实际上都是数据为主的。例如, ( r$ ~* @8 j. g' g8 Z8 Z
考虑在Amazon.com网站上显示一本书的各种信息的页面,虽然这个页面是一个相当巨大的文 6 A# j7 r8 Z/ ~; W$ K1 ^% |8 s
本,但是这个文本的结构是高度规范的,所有页面都包含有介绍书的共同点,并且每一页中文本 2 z) H/ [( g4 t% K3 g, w8 q的大小是受限制的。也就是说,它可以从一个简单的、数据为主的XML文档 + 包含有每一页信息 2 S3 o- d4 p2 I) a的数据库+ XSL样板文件 就能够实现这个网站的结构了。通常,目前任何一个动态建立HTML的网 / h- F$ |8 Y, f" |7 i+ x G
站都可以被上面介绍的这种结构来实现的。 # i5 |& ?7 r! O$ E5 y2 N
下面是一个很简单的例子: 3 k8 D$ T0 y3 q. [8 s5 ~ <Lease> " t( ~/ B h+ v
<Lessee>ABC Industries</Lessee> agrees to lease the property at r) e; T" q- \% K+ r A" c* z+ s
<Address>123 Main St., Chicago, IL</Address> from <Lessor>XYZ # J* \2 H* b: @# u Properties</Lessor> for a term of not less than <LeaseTerm " C: Q v- r& eTimeUnit="Months">18</LeaseTerm> at a cost of <Price : q7 Q5 Q* V- ~- s5 p2 u3 PCurrency="USD" TimeUnit="Months">1000</Price>. , |1 J$ r" d) W7 B. W' z4 I </Lease> 7 R, ~3 R3 r+ v5 g它是使用下面的这个XML文档和一个简单的样板文件实现的: 6 d9 ~6 a" E# x _+ M7 q
<Lease> $ [: i; @: K. j# G1 b% z
<Lessee>ABC Industries</Lessee> 0 ^0 m; e8 A- s- x8 L/ }7 o <Address>123 Main St., Chicago, IL</Address> ! L1 v) F# `, v; _ <Lessor>XYZ Properties</Lessor> ; m* ]3 W; ?5 e% W6 r
<LeaseTerm TimeUnit="Months">18</LeaseTerm> D$ X1 d+ w- D
<Price Currency="USD" TimeUnit="Months">1000</Price> 8 p- M& ~2 f+ X$ q- E2 C/ P
</Lease> 7 S- l" W+ e8 |6 i! G6 [, {
' T$ ?1 i( b$ F# f3.2 以文档为主的文件 & A; l: }7 z9 x: } ~/ }1 T" j( z
以文档为主的文件表现出来的特点是:不规范的结构,大量的原始数据(就是说, * U$ |/ \! V8 {最小的独立数据单元是包含有混合内容的元素级或则本身就是一个文档),和大量混合内容。其中 ) h9 {5 i* R; C2 |4 N! ]2 R, I同类型元素和PCDATA出现顺序是非常重要的。例如一本书,一封电子邮件,广告,以及几乎所有的 # h5 s( L" _4 r9 J7 a" }
XHTML文档。以文档为主的文件通常是用来设计人文消费: + t0 Z) M# {- F, \! U; t
例如,下面的产品描述就是一个以文档为主的文件: 4 d' j. a4 V# [5 u' F" t* A: t
<Product> % x# G$ J, D; j. U& t; S% [ <Name>Turkey Wrench</Name> 6 D8 n7 S. \' g$ U# _; G
<Developer>Full Fabrication Labs, Inc.</Developer> 4 y9 t$ B$ A) E <Summary>Like a monkey wrench, but not as big.</Summary> ) E' F0 e% g. v9 ? <Description> / u0 \5 b/ C- J/ S
<Para>The turkey wrench, which comes in both right- and . i3 P- H; a0 R, a left-handed versions (skyhook optional), is made of the finest 7 z5 g# u( D3 W( X1 c4 { stainless steel. The Readi-grip rubberized handle quickly adapts ( D/ O3 r0 ]; s2 Z to your hands, even in the greasiest situations. Adjustment is ) g; m% ~: u9 r/ y% ` possible through a variety of custom dials.</Para> 9 Y8 I& H5 |# @ <Para>You can:</Para> ) L2 X; T- U" D; _
<List> 7 G# l" l2 s1 x5 M E <Item><Link URL="Order.html">Order your own turkey wrench</Link></Item> $ |7 c9 K/ y" t& q1 m <Item><Link URL="Wrenches.htm">Read more about wrenches</Link></Item> 1 V7 v8 l, B8 H. ~! |9 v <Item><Link URL="catalog.zip">Download the catalog</Link></Item> ( @/ j2 U' l! h$ h, M( W
</List> 5 |' `' `2 o M% o r. u <Para>The turkey wrench costs just $19.99 and, if you & l3 I z! `- Z2 u6 N
order now, comes with a hand-crafted shrimp hammer as a ~* H+ k) @+ s: C1 o7 A6 M
bonus gift.</Para> . @& Z5 z& b$ d9 u2 s% G </Description> + d7 t' S( U- u5 R/ i
) m! s8 X( }" }; X" b8 f O% g3.3 数据(Data)、文件(Documents)和数据库(Databases) 2 f" H! @$ x# Q( ~6 W) w
事实上,数据为主的文件和文档为主的文见之间的区别并不是很清晰。例如,虽然 / T1 Y- ~7 E4 U* A. C: C. h( |一个数据为主的文件(例如一张发票),也有可能包含大量的不规范结构的数据,例如发票的描 : B: @) ?2 o$ ]# o; }. }3 x) {述部分。而一个以文档为主的文件(例如用户手册),也可能包含有规范的数据结构(通常是元数 - S1 V4 t+ m& y$ d% G# j& q. R
据metadata),例如作者名和再版日期。除了这些,你用来判断是否是两者中其一的另外 / y% N0 v \3 h# |- m8 l& c3 c" u2 j& Y: s一个重要特点是你是对数据还是对文档感兴趣,这也将决定你要采用什么样的系统。 - I; j' S/ o6 j4 q" W: C' J
要存储和获取数据,你可以使用一个数据库(通常是关系数据库,面向对象数据库 6 y6 H4 |' n; h! i或则树状体系数据库)和中间件,或则你也可以使用XML服务器(你可以把它看成是将数据库 2 r/ d* }: T0 Z1 d+ z$ o
和中间件捆绑在一起)。要保存文档,你将需要一个内容管理系统。有关各种系统的探讨 w: Q, |+ C/ f/ I在第4.0小节中, "存储和获取数据"和第5.0小节 "存储和获取文档".你能够在第6.0小节找到 7 B7 P' ^5 M, y- l' a6 c( h一些可使用的软件列表"可利用的软件"。 * [, f4 w \/ |2 q2 j: m
" X: \# N v$ y) g' V
4.0 存储和获取数据 - K1 r! J8 o0 m4 \5 s9 O
数据的类型可以在数据为主的文件的原始定义或则从数据库中的字段类型中得到。 0 m5 o, G' k6 ]- G! k8 C
前者的例子是你想把数据库中的数据保存成XML文件放到网站上;后者的例子是你需 - ~5 X0 I% O0 w3 x1 N. ^要把大量的数据保存到关系数据库中。根据你的具体需求,你需要的软件或则是把XML数据 3 Z: R) {+ f/ e# |+ u- A
读入到数据库或则是把数据库中的数据输出到XML文件,或则两者都支持。 ( Y @1 L% i+ h4 [2 |- W
( C3 i7 J2 M$ j7 T H9 L. Y g
4.1 转录数据 - y/ U6 W$ Q$ d/ t% @2 p+ \4 ^' n
当将数据保存在数据库中,它经常需要抛弃与文档信息有关的大量内容,例如它的 ) ~. M4 p4 ~& b; O% H3 |8 \' C名称和DTD,同时还有它的物理结构,例如实体的定义和使用、属性值和相同类型元素的出现顺 - Z$ E& ~. n/ ]( I- s
序,还有二进制数据的存储方式 (是经过Base64编码的还是没有经过编码的实体或则其他方式), / l. t, ?4 T% g8 F+ W* P
CDATA的内容和其他编码信息。简单而言,当从数据库中获取信息时,最后生成的XML文档结果可 0 K7 v! {+ o* d' u6 u+ d+ ]能不包含任何CDATA或则实体运用(entity usage) (除非预先定义了实体lt(就是符号"<" / u4 g& l& T% a. n& D4 |$ u& }
),gt(">", amp("&", apos("'", quot(""")和同类型元素、属性出现的顺序。 6 b- C- E) }) S$ W' z7 z# V5 [ 例如,假设你需要把一个销售单的信息使用XML格式从一个数据库中获取数据然后转 $ ], Q( {9 T s+ V5 Z& N+ m( D
录到另外一个数据库中,在这个例子中,在XML文档中并不关心销售单的编号是保存在销售单的日 ' H2 n' R8 F4 m. x2 g8 D/ O* L
期的前面还是后面,也不用关心是否将顾客的名称保存在CDATA section作为一个扩展入口, 7 `3 A+ U" _' t: f& ]6 J) ?4 T4 E( Y或则甚至直接当成一个PCDATA. 但是,对于将这些相关数据从第一个数据库中转录到第二个数据 6 q4 _( T7 b( @& x库的过程中,这些信息都是非常重要的。这样,这个数据传输软件就需要考虑使用树状结构 , P1 B: v ?7 e& T/ `0 _9 T, K; v(它将一个单独的销售单的信息用组(group)来实现)。 4 J+ u# x, e7 W 另一个当忽略文档信息和它的物理结构会带来麻烦的例子是---"借贷套利"文档,它 0 M& o6 E4 J# x* }* M
保存的数据是从一个数据库中的文档中获取,并且需要重新组装这些数据成为一个新的文档, # G# `, W3 f \, z
而这个过程经常会导致新的文档的结构和原来的文档会不一致。 0 C: }) K' C% M# E1 B% e
从上面的例子可以看出,对于数据库和数据传输中间件的选择是根据你的需求而变 0 Q, l1 k% A& Q& J: d. X) F化的。作者: 帅哥 时间: 2008-10-25 17:41:13
4.2 将文档结构映射成数据库结构 / @# N6 x9 R! c- }! O: r; A, }
为了能够在XML文档和数据库之间传递数据,有必要将文档的结构映射成数据库的结 % W- v8 s9 {2 W$ T6 U8 W/ a! x构,反之亦然,这种映射关系又分两类:模板驱动和模型驱动 - f N! [* l I6 V9 Z6 p! R* j9 r) T9 H2 X W) W E9 m
4.2.1 以模板驱动的映射 * \+ z% R7 z( G$ y: R2 P- X 以模板驱动的映射, 这种映射没有预先定义文档结构和数据库结构之间的映射关系 6 p2 |! S5 V6 M
,而是使用将命令语句内嵌入模板的方法,让数据传输中间件来执行该模板。例如,考虑下面 ' o+ o4 j( `8 N6 _4 l$ z3 h/ X
的模板(注意该模板并不适应与所有的产品),在<SelectStmt>元素中内嵌了SELECT选 $ U/ e+ F/ D! {* S6 s8 [, ~择: # p1 M2 [+ A) P; E' X( k
<?xml version="1.0"?> . ?# S5 f$ n5 x4 R: {/ t
<FlightInfo> ( Z" m1 n9 \6 [2 A <Intro>The following flights have available seats:</Intro> + t; c, l* P* S& M2 o& D/ H8 ] <SelectStmt>SELECT Airline, FltNumber, Depart, Arrive FROM Flights</Se 3 Y& V+ N6 T( f/ [
lectStmt> ! k7 @3 K) W) ^ L. f
<Conclude>We hope one of these meets your needs</Conclude> * q3 c2 z% c7 `
</FlightInfo> " q7 G7 ?3 u. S 当数据传输中间件处理到该文档时,每个SELECT选项都将被他们各自的结果所替换, ) m2 m4 H) }5 q, G" \ I
1 s$ h; G- j( J0 C9 ] 得到下面的XML格式: 6 ]3 `3 z1 ?* @+ h+ I <?xml version="1.0"?> 3 K. ]4 k7 a# h) i9 u" p: s8 H) I) E
<FlightInfo> % L' w0 |/ E' x$ x4 ~' y
<Intro>The following flights have available seats:</Intro> 1 ~2 r/ }1 [ J% n! w <Flights> 6 I) ~. V# F- y; U! `* C% a
<Row> + r8 j- Q) v' B% w2 S <Airline>ACME</Airline> 9 y8 M0 @- m0 G( r1 I2 x
<FltNumber>123</FltNumber> 6 u* r0 o% l9 [- R <Depart>Dec 12, 1998 13:43</Depart> # s v A2 V4 w7 F <Arrive>Dec 13, 1998 01:21</Arrive> 3 P B+ W0 y# b! ]. L
</Row> 2 \0 U# [. R! K' U4 U# D: w9 J! f$ y& H ... " W7 f# Z2 u$ c8 ~
</Flights> 9 X3 A$ Y8 Z% K% _ <Conclude>We hope one of these meets your needs</Conclude> $ q" b( j5 @# [+ z( x7 c
</FlightInfo> . J' l; c ?; S- |$ G; Y 这种以模板驱动的映射方法相当灵活。例如,一些产品允许你在最后的结果中替换 + t, w! m7 v; l O. w+ z9 x
你想要的内容 -- 包括在SELECT中使用参数 -- 而不是象上面的例子中简单地格式化结果。 ' u* y9 O; g; j, F4 p另外它还支持使用编程结构例如循环和条件判断结构。还有就是它支持通过HTTP的传递 1 n- L+ s' Q7 j
参数。 - T' _( p- J7 O/ s, P8 U2 z 目前,以模板驱动的映射仅仅只支持从一个关系数据库转换成XML文档的情况。 * r) q _% [/ M% @; [. E
* F' |+ A# K3 j/ c' E& X
4.2.2 以模型驱动的映射 7 A' Z! V# |0 Q2 {
在以模型驱动的映射模式中,它的原理就是利用XML文档中的数据模型的结构显性或 9 d& m- u4 P$ r5 n8 n C) I: C
隐性地将其映射成数据库的结构,反之亦然。它的缺点是灵活性不如模板驱动方式,但是优点 3 b6 ~& A8 |6 _5 H
是简单易用,这是因为它是基于具体的数据模型来进行映射的,通常它能够自己完成很多地转 3 N2 p- Y/ \# Q. G' n" b换工作,从而简单易用。因为将数据从数据库转换成XML的工作是根据单一的一个模型(模型), : x9 D, H& S: f! q" k% y所以通常在这种方式下还要综合搭配XSL来提供灵活性。 * U# ~. K% Q! ^1 [: e+ |& \ 在XML文档中有两种模型是非常普遍的。第一种是被许多中间件包在转换XML文档成 5 C( t# J5 {* |
关系数据库数据所使用到的模型,就是将XML文档当成一个单独的表(Table)对象或则一系列表对 : r0 q8 S& U. J7 J7 Y7 \7 e$ U象。也就是说,真正的XML文档必须类似于下面的格式,如果是单一的表对象的话,<databa + h( e) U9 _$ z5 t
se>元素就不需要出现了 2 Q+ l9 ?9 d$ w8 Y, `/ ~- f
<database> y! z+ K9 a, C. @& I. k <table> * l& a8 M! K, Q
<row> % b, j: c5 b, |; j
<column1>...</column1> ' s: p" J/ x( I9 q. L' ]$ r
<column2>...</column2> 0 l, B6 P. {% q& t1 b4 `' r: r ... 6 g% A. n' r7 r; z0 }
</row> ( i* V' l+ R4 H6 l
... 6 o5 M" k+ L! W+ Z" m </table> / m$ G- M6 f; n% f! ~# p- f, x" o& r ... : ?. w" T! e1 ]$ ~ </database> F6 F6 _+ j; C6 [. E! s$ O 其中的"table"可理解为单个的结果集 (当数据是从数据库往XML中传输时)或则是 3 j+ G* ]. j5 Q一个单独的表对象或则一个可更新的视图(view)(当数据是从XML往数据库传输时)。如果数 2 a' U' Z4 V3 f2 d
据是来自多个结果集的描述中(当数据来自数据库中时)或则XML的文档包含有更深层次的嵌套 * p% ^6 s/ K# ^
元素,有必要表现成一系列表对象 (当数据要转换到数据库中时),那么类似与上面例子那么 8 E c V8 [: S/ b6 [; @0 }简单的传输是不可能的。 2 i" l9 |/ v$ H0 l- _
第二种普遍的数据模型是XML文档种的对象树,在这种模型下,元素通常对对应了 + a4 U$ u* e1 c9 a! d一个对象或则属性或则PCDATA对象。这种模型直接映射成面向对象的数据库和树状结构 . P) |1 D Q1 D
数据库,当然借助传统的对象-关系映射技术和SQL 3对象视图也可以映射成关系数据库。要注意 4 ]: z6 ?$ `6 D* o: ? e* @/ W的是,这种模型并不是文档对象模型(DOM),DOM是指文档本身是个模型,而不是指文档中的数 6 `1 ~# l6 w$ p! q$ y4 d9 Y3 `7 l据。 . R& I- n5 `: g1 C& b# B 举例,在上面介绍的销售单文档可以被看成是有5个类的对象树---Orders, SalesO 9 F) F+ Z1 \; u3 Y' y# Crder, - w4 Y0 Y. i6 e/ V
Customer, Line, and Part -- 入下图所示: / Z( T/ C5 x1 G; ] Orders 4 |% k1 m3 T( u' {; L& Z3 e! i- t- b4 m
| 3 G- I. K P. V c$ O' S8 R! Q8 \
SalesOrder $ z- z; ~, c; {- }) V( k
/ | \ 4 s* D& U5 D+ C
Customer Line Line % J: P" b, b$ E: ~5 Q8 l. H
| | ( O8 C' t# J* u+ ]& ~ Part Part 5 H+ j, r7 p2 d 当一个XML文档模型化处理成一个对象树时,对元素和对象不需要什么特殊的要求。 ) _8 R/ M' M A0 w* n. ` Y. a例如,如果一个元素只包含有PCDATA,例如销售单文档中的CustName元素,它能够被看做一个 6 z$ g( b+ n# k! b
属性进行处理(就是仅仅只包含有单独的数值)。简单来说,有时将混合元素或则元素内容 2 [2 n! V+ K% K, l0 n8 S0 J; ~2 S模型化处理成属性是非常有用的方法。一个现成的例子就是在销售单文档中对Description元素 / W7 f8 U3 o9 _- E
的处理:尽管它在XHTML的Form中有混合的内容,但是将description元素看作一个单独的属性来 6 B- W: R7 f2 x! e+ ^! X0 X+ f, x
处理会更有用些,因为它的组成部分就本身而言没有什么意义。 9 a/ c6 i" c- O% o& F 4 m$ A) o% e5 U, [) g) a, F4.3 数据类型, 空值(Null), 字符集设置和其他所有的类似集 9 Y8 C6 H' U% y6 r3 k1 H: k0 f8 p% ?
本节将探讨一些和将XML文档转换成数据库之间有关存储数据的内容。通常,你在选 " k! @) T# v/ O2 H1 N3 S3 \/ M) c
择什么样的中间件来解决这些问题的时候是不会考虑到这些问题的,但是如果你注意到这些问 $ q0 U2 r! m( e4 k
题的存在时,希望下面的讨论对与你在选择中间件时有所帮助。 ) h) e) d# w. F" i* g2 C 2 Q9 p2 k, W8 f' j1 L5 J4.3.1 数据类型 9 C" b. v/ A' I; J, h2 e XML不支持任何有意义的数据类型,除非是不能够解释的实体,所有XML文档中的数 - Z# S3 d3 L& Q. v; F0 d6 _据都被当成文本(text)来对待,虽然它能够用其他的数据类型来表示,例如可以表示成日期 & ]. P. \# N" a& J- h; ~( P0 Z0 h
或则整数。通常,数据转换中间件将把文本(在XML文档中的文本)转换成其它的数据类型(数据库 9 Y" B5 P( Y1 O# Z3 H2 D m
中的数据类型),反之亦然。然而,一些特定的数据类型在转换的过程中是受限制的,例如受那 6 _4 r0 |: _2 y% a8 |些提供数据支持的JDBC驱动的限制。在这些众多的有可能的数据类型中,日期类型通常会导致 : Q! s; F' k \( _6 s v麻烦。数字,特别是由于国际地域不同的数字格式,也可能导致问题。 1 t+ j. j/ K; N/ i
2 ^$ D2 {0 x' i" N1 R, b* B/ z4.3.2 二进制数据 2 {# r; V" G. H3 c
有两种比较普遍的方法将二进制数据保存到XML文档中:对实体不做任何编码处理和 ' x) g3 q/ W$ A1 f, r; W, w# P对实体进行Base64编码处理(一种MIME编码方法,可以将二进制数据影射成US-ASCII的子集)。 S4 T P, ^9 Z! Y$ z对于关系数据库,这两种方法都被证明是有可能存在问题的,因为大家都知道当保存和获取二进 ; S1 h% P# ~, M- L9 f% R7 B制数据到数据库中的规则是非常严格的,这样对中间件将有可能导致问题。另外,并没有一种标准的符 1 N$ b2 E q( x6 \8 H6 O号用来说明一个XML文档中的元素包含有Base64编码数据,从而中间件可能根本就不能够识别这 + e1 @' X& A' j o. U& i
种编码。最后,还有可能有些中间件在将数据存储入数据库的过程中根本就会忽略没有编码实体 ) m) c) `. s) M7 E中的符号或则Base64编码中的元素。所以,如果对你而言,二进制数据非常重要的话,请千万要 : P/ \) j D( O& A8 x: r% v( X/ w3 U确认你的中间件是否支持二进制数据。 1 d- Q1 e6 Z8 x. c# L2 T1 n3 T0 u% g/ h
4.3.3 空值(Null) ( S. ?7 _ z) N3 P$ |1 S& @* E 在数据库世界中,null数据意味着数据不在那。这不同与一个值为0(对数字类型数 ! J' M6 L% M( u' ?$ I x- V% g
据)或则长度为0(对字符串类型)。例如,假设你的数据是收集自一个气象站, 如果气象站的温 . p, a: l2 J7 a, H$ D度计出毛病了,那么你的数据库中将存储一个null值而不是一个0,值为0完全是另外一回事了 4 ^) w/ x) r/ P' g( \。 & v5 ^* D* ?1 H- X. t) @ XML也支持空值的概念,可以通过设置元素的类型和属性来实现。如果元素类型或属 / F( v8 i( b, y% }" v性的值为null,XML的处理方法是简单地不将其包含到文档中。但是对数据库来说,空的元素 ) A4 B# @' G" R5 N& T r. V: l5 l或则包含0长度字符串的属性并不意味着null:他们的值是长度为0的字符串。 6 c# g+ L% ?+ w! {/ } 当将一个XML文档结构映射成数据库或则反过程中,你必须特别注意那些可选的数据 8 ^6 m6 G9 o( X$ D6 v0 g
类型和本来表示空值的属性。如果不这么做的话,结果将是可能出现插入错误(当将数据转换 7 U1 s/ H3 n! r2 q3 G到数据库中时)或则非法文档错误(当将数据从数据库读出时)。 * `" P$ L0 [: X; [+ h; {( U 因为XML中相对与数据库而言在对符号意义的申明有更好的灵活性 --- 具体来说, . J; F' m' `/ u, L% e
就是XML用户愿意将空元素或则包含长度为0内容的属性认为是"null" -- 你必须根据这个考虑选 + u0 T5 _* w9 `择什么样的中间件来处理这个问题。一些中间件提供给用户自定义在XML文档中什么标志是表示 8 j" v' O% |. u+ T+ k"null"的。 & c# M8 z; h7 G% k8 ~+ V/ M. ~
0 T/ d6 j4 s8 A I9 e
4.3.4 字符集设置 z; q8 a% A' E1 c3 O9 l9 w ^
根据定义,一个XML文档能够包含任何Unicode字符,除了一些特殊的控制字符。但 5 Z& m: }" p( o* X4 E是不幸的是,许多数据库都限制或则不支持Unicode并且需要一些特殊的配置才能够处理非ASC 9 }1 q( `$ R" J
II 编码的数据字符。如果你的数据包含有非ASCII字符,那么请确保你的数据库和中间件是否能够 ; _/ }" o" y5 y/ B0 I: q0 Y处理这些字符集。 - E& s' ?3 }) Z( F' P/ M: G$ I) G. r
4 p- r4 s% X* J' U4.3.5 处理指令(Processing Instructions) * Z9 T) t2 \( m2 x! |6 Z 处理指令不是XML文档中的“数据”部分,目前许多中间件都不能够正常的处理它们 9 l* L. Z0 q1 U# {1 E: ^( W: o" B: A
。问题是这样的,尤其是在一个严格的将XML文档结构映射成数据库结构中,处理指令通常 + d" C3 T9 s1 J* ]! t) A& n& e: a) J是很难处理的,因为题目可以出现在文档的任何位置,于是,中间件就非常困难的需要判 . l* B6 W5 K2 k6 U, r8 b
断将它们保存到什么位置和读取的时候取回到什么位置。如果处理指令和文挡的"round-t 5 W3 O9 {" a& s- L; ?) J. _! B+ |' Wripping"对你而言是非常重要的话,你就必须确保你选择的中间件能够处理这个问题。 ( @0 ~' T4 p+ I6 c% x) t3 j3 o5 a! N! K7 J) l$ j& `1 L6 s
4.3.6 存储标志(Storing Markup) 2 x2 B) m, n; A, B' O 在4.2.2小节中提到,有时候直接将包含有元素或则混合内容的元素不进行进一步的 - X- q0 p& L$ a6 B7 I% N* h$ m, m
解析直接保存到数据库中是非常有用的。最普遍的实现方法是简单的把这个标志本身直接保 ' K- S# C# e- G" Q& k0 P( t
存到数据库中。不幸的是,这将带来另外一个问题,当从数据库中读取这些数据时:将很难 * E: d4 R: l1 ]* j+ `3 H# p0 i
判断数据库中的标志到底是真是假,特别是一些由lt和gt转义的字符。 7 q- ] b9 Z0 q4 p/ X, B0 c
例如下面的描述: 9 ?/ F Q) G7 s6 b
<description> - m8 _2 x5 v# V2 e
Confusing example: <foo/> : h& z5 z9 `" X# p' B0 d </description> # ~; D3 T; `- l; k& Y# o7 g
保存到数据库中将变成这样: " M; S, B* e- N' x9 } n Confusing example: <foo/> 0 t; b5 h% U3 @6 [ 这时数据库将不能够判断和<foo>是标志还是文本了。解决方法有以下几种,例如 # x% v U( X1 Z" R& U9 v
将标志的符号使用其它非标志符号替代,但是这时你要非常的小心,因为也许别的运用程 # ^! Z$ \; @4 w+ U `& @序在使用这些数据时就会出现不兼容的现象。例如,如果你想查询数据库中的小于号("<"和 ) z8 \7 {$ G5 U0 Wlt标志("<"时就要特别小心了。 4 H7 f$ |6 X9 A3 p0 ^7 d
/ K) \% y# m( x0 i, E4.4 从数据库的结构生成DTDs和逆反过程 ' T" @7 @3 c6 {. @ S) O在XML文档和数据库之间转换数据的一个普遍问题是:如何从数据库的结构生成D & F) ]8 V: N* W: h" m L0 sTDs和其逆反过程。简而言之,目前有许多软件都提供了可以直接使用的操作功能,但是它 / C9 G& d7 z; s. J- F' i产生的结果对许多用户来说用处和帮助不大,也许没有多少人喜欢。 t7 S. s' }# Q6 S3 Y: x例如,下面的过程(已经简化过的)就是从一个XML文档到关系数据库中生成DTD的 ) h- x1 y: h% @; o& f1 A' O) o6 _: V
:对每一种包含有元素或则混合内容的元素类型,新建立一个table和一个主关键字段。 4 n. o/ s0 z, K% Y
对混合内容种的每一个元素,建立一个分开的table,在其中保存PCDATA,通过主关键 2 a+ n* T, Y, T) f, Y' Y' Z
字连接到父表中。 + s" b! @3 r" G% P对于元素类型中每个有单一数值的属性和只包含有PCDATA内容的子元素类型在该ta . t! \0 w% v! s, N( U' ~/ X( H
ble中新建立一列(字段)。如果子元素类型或则属性是可选的,让该字段允许为空。 1 R/ M5 e8 r# v# e$ x对于每个有多值的属性或则多仅含有PCDATA内容的子元素类型,再建立一个分开的 ) Z, h# ]2 q1 E: K9 {+ _table来保存他们的值,通过它们的父表的主关键字连接到父表。 0 t, \& n9 d* D$ j' y2 E% r ^
对于每个子元素,这些子元素本身还有元素或则混合内容,使用父表中的关键字将 3 x9 ^0 i4 O( w/ z* z# u
父元素表连接到子元素表中。 - f5 I: \0 h7 h& A, e0 O3 E7 J- S而下面则是一个从关系数据库的结构生成XML文档的过程(简化过的): $ m1 o9 M$ h! G( L对每个table,新建一个元素。 3 x4 v3 s" D6 T% @9 u
对表中的每列,建立一个属性或则只含PCDATA的子元素 . k7 [/ I9 y5 p H/ w- M2 z+ w% @对每个包含有在主键/外键关键字关系中主键值的列,新建一个子元素。 ! z- ~5 a8 k; b4 \- ]" P
不幸的是,在这些过程中存在许多缺陷。例如,其中没有实现对数据类型的预先定 0 G- |, M6 u; M0 y/ f. m7 k+ s义和在DTD中没有实现对列长度的预先定义的方法。因为任何的预先定义,例如通过读一个 1 o1 M$ i p8 Q2 u0 }1 n
示例文档,当读取其他“类型”的文档或则其他文档中包含有超过字段长度内容的文档时, , f+ K, ^' b, u7 G; Z9 B就会发生错误。(解决这个问题的办法时使用XML schema文档中数据类型定义)简单来说,当从一 5 |1 |+ s' G% e个关系结构中生成DTD时,是没有办法预先判断子元素“应该”出现的顺序或则类似数据库中的 1 B. L1 L/ E% U5 i
行标识。 C! |( N# `" \4 R( J5 @. l尽管有这些陷,根据数据库结构生成DTDs的软件能够给我们带来了一个很好的开端,特别是对与 % i/ f4 P1 ]' X: e/ G那些非常庞大和复杂的系统。