540 likes | 719 Views
第 23 章 XML. 动机 XML 数据结构 XML 文档模式 查询和转换 XML 应用程序接口 XML 数据存储 XML 应用 总结. 简介. XML: 可扩展标记语言( Extensible Markup Language) 由 WWW Consortium (W3C) 定义 SGML(Standard Generalized Markup Language) 的子语言 根源 : 对文档加标记 ( 注解 ) 标记 (markup) 的早期用途: 如标出内容文本的排版格式 现在的用途: 如指示内容文本的功能或语义
E N D
第23章 XML • 动机 • XML数据结构 • XML文档模式 • 查询和转换 • XML应用程序接口 • XML数据存储 • XML应用 • 总结
简介 • XML:可扩展标记语言(Extensible Markup Language) • 由 WWW Consortium (W3C) 定义 • SGML(Standard Generalized Markup Language)的子语言 • 根源: 对文档加标记(注解) • 标记(markup)的早期用途: 如标出内容文本的排版格式 • 现在的用途: 如指示内容文本的功能或语义 • 标记的形式: 标签(tag) • 例如:<title> XML </title> <slide> Introduction …</slide> • 可扩展 • 不同于HTML, XML没有预定义的标签集合,应用可根据需要选用自己的标签集合
动机 • XML用于数据表示及交换 • 不同组织之间的数据交换对于今天的网络化世界是关键的 • 例如: • 银行业: 资金转帐 • 订单处理 (特别是公司间的订单) • 科学数据:化学ChemML,遗传学BSML,...... • 组织之间的纸张信息流正被电子信息流所取代 • 每个应用领域都有自己的一套信息表示标准 • 在文件中存储结构化信息 • 与DB中的数据存储相比, 效率不高;但便于交换, 以及在文件中存储复杂结构的信息.
XML的优点 • 标签使得数据是自描述的(self-documenting) • 不需查看模式即可理解文本的意义 • 文档格式不严格 • 接收者对预期之外的标签可以忽略,相似数据的标签未必全同 • 数据格式可以随时间演化, 并且不使现有应用失效 • 同一标签的多次出现易于表示多值属性 • 允许嵌套结构 • 同一结构可嵌套于多处(冗余), 有利于与外部交换数据 • 规范的关系表示(分解为多个关系)避免了这种冗余 • 存在大量的工具帮助处理XML数据 • API • 浏览器 • 数据库工具
半结构化数据模型 结构化数据一般需要用一个单独的模式来描述其结构 优点: 高效实现存储和查询处理. 半结构化数据是自描述的, 即数据自身携带有关其模式的信息. 优点: 可以灵活添加新的属性和关联, 即模式是可变的 描述现实世界更灵活 非常适合异构数据库的集成. 5 Lu Chaojun, SJTU
半结构化数据模型的图表示 半结构化数据库是结点集合 结点: 相当于对象 叶子结点与原子类型数据关联. 内部结点有引出边. 根结点没有进入边, 表示整个数据库 边上有标注, 表示目标结点与源结点的联系. 对标注没有限制, 可以表示属性或者联系. 6 Lu Chaojun, SJTU
半结构化数据的图 有根图 takes sno name cno 007 j.bond CS123 7 Lu Chaojun, SJTU
例子 Root bar beer beer manf manf name prize Bud A.B. name year award M’lob servedAt 1995 Gold name addr Joe’s Maple 8 Lu Chaojun, SJTU
XML数据的结构 • 元素: 从<tagname>到</tagname>之间的所有文本 • 每个文档必须具有单一的根元素 • 元素必须合适地嵌套 • 合适的嵌套 • <account> … <balance> …. </balance> … </account> • 不合适的嵌套 • <account> … <balance> …. </account> … </balance> • 形式地: 每个开始标签必须具有唯一的匹配结束标签, 并位于同一父元素的上下文中.
XML数据的结构(续) 在XML中文本与子元素的混用是合法的. 例如: <account> This account is seldom used any more. <account_number> A-102</account_number> <branch_name> Perryridge</branch_name> <balance>400 </balance></account> 这在文档处理系统中有用, 在数据处理系统中没有什么意义. 在数据库系统中对表示结构化数据尤其不适合.
嵌套元素的例子 嵌套能力提供了表示信息的其他方式 <bank-1><customer> <customer_name> Hayes </customer_name> <customer_street> Main </customer_street> <customer_city> Harrison </customer_city> <account> <account_number> A-102 </account_number> <branch_name> Perryridge </branch_name> <balance> 400 </balance> </account> <account> … </account> </customer> . . </bank-1> 嵌套表示广泛用于数据交换应用, 以避免联接
属性 元素可具有属性 <account acct-type = “checking” > <account_number> A-102 </account_number> <branch_name> Perryridge </branch_name> <balance> 400 </balance> </account> 属性是在元素开始标签中用name = value对来说明的 一个元素可有多个属性, 但每个属性名只能出现一次 <account acct-type = “checking” monthly-fee=“5”>
属性 vs.子元素 • 子元素与属性的区别 • 在文档处理场合, 属性是标记的一部分, 而子元素内容是基础文档内容的一部分 • 在数据处理场合, 两者区别无关紧要 • 同一信息可有两种方式表示 • <account account_number = “A-101”> …. </account> • <account> <account_number>A-101</account_number> … </account> • 建议: 用属性表示元素标识, 利用子元素表示内容
名字空间 • XML数据需要在组织之间交换 • 同一标签名在不同的组织中可能有不同的意义, 从而导致对所交换的文档的混淆 • 使用具有唯一性的字符串作为元素名字可避免混淆 • 更好的解决方法: 使用unique-name:element-name • XML名字空间 • 在标签和属性前加上一个URI(如网址URL) <bank xmlns:FB=“http://www.FirstBank.com”> … <FB:branch> <FB:branchname>Downtown</FB:branchname> <FB:branchcity> Brooklyn </FB:branchcity> </FB:branch>… </bank> • 一个文档可以使用多个名字空间. 缺省名字空间可用xmlns=来说明
XML语法的更多细节 • 没有子元素或文本内容的元素可简化为以/>来结束开始标签并删除结束标签 <account number=“A-101” branch=“Perryridge” balance=“200 /> • 为存储可能包含标签的字符串数据, 而又不将标签解释为子元素, 如下使用CDATA <![CDATA[<account> … </account>]]> • 这里<account> 和</account> 只是视为字符串 • CDATA表示“character data”
XML文档模式 • 数据库模式约束了可以存储什么信息, 以及存储的信息的数据类型 • XML文档并不要求必须具有一个关联的模式 • XML的自描述性质使得文档可以不要模式 • 但是, 模式有时很有用 • 作为应用的一部分被自动处理 • 大量相关数据用XML组织 • 模式定义语言 • 文档类型定义 (DTD) • 是XML标准的一部分, 广泛使用 • XML Schema • 较新, 应用越来越多, 将取代DTD • Relax NG
文档类型定义 (DTD) • XML文档的类型可以用DTD来说明 • DTD约束了XML数据的结构 • 可以出现什么元素 • 元素可以/必须具有什么属性 • 每个元素内可以/必须出现什么子元素, 以及出现多少次. • DTD 不约束数据类型 • 所有值都表示为XML中的串 • DTD 语法 • <!ELEMENT element (subelements-specification) > • <!ATTLIST element attributes-specification >
DTD中的元素说明 • 元素可定义为 • 嵌套子元素正则表达式, 或者 • #PCDATA (parsed character data), 即文本数据内容 • EMPTY (无内容) 或ANY (任何东西都可作为子元素) • 未加以定义的元素等价于显式定义为ANY类型 • 例如 <! ELEMENT depositor (customer-name, account-number)> <! ELEMENT customer-name(#PCDATA)> <! ELEMENT account-number (#PCDATA)> • 子元素定义的正则表达式 <!ELEMENT bank ( ( account | customer | depositor)+)> • 表示法: • “|” - 可替换选择(or) • “+” - 出现1 次以上 • “*” - 出现0 次以上 • “?” - 出现0 次或1次
Bank DTD <!DOCTYPE bank [ <!ELEMENT bank ( ( account | customer | depositor)+)> <!ELEMENT account (account_number, branch_name, balance)> <! ELEMENT customer(customer_name, customer_street, customer_city)> <! ELEMENT depositor (customer_name, account_number)> <! ELEMENT account_number (#PCDATA)> <! ELEMENT branch_name (#PCDATA)> <! ELEMENT balance(#PCDATA)> <! ELEMENT customer_name(#PCDATA)> <! ELEMENT customer_street(#PCDATA)> <! ELEMENT customer_city(#PCDATA)> ]>
带有DTD的XML文档 随XML文档 <?xml version=”1.0” standalone=”yes”?> <!DOCTYPE GREETING [ <!ELEMENT GREETING (#PCDATA)> ]> <GREETING> Hello XML! </GREETING> 独立文件 <?xml version=”1.0” standalone=”no”?> !DOCTYPE GREETING SYSTEM “greeting.dtd”> <GREETING> Hello XML! <GREETING>
DTD中的属性声明 属性声明: 对每个属性要声明 属性名字 属性类型 CDATA(字符数据) ID (标识符) 或者 IDREF (ID 引用) 或者IDREFS (多个IDREF) 缺省值 缺省值: 读入文档时, 若属性未指定值, 则自动填充缺省值 #REQUIRED: 文档必须为属性指定值 #IMPLIED: 未提供缺省值, 文档可忽略此属性 例如 <!ATTLIST account acct-type CDATA “checking”> <!ATTLIST customer customer_id ID # REQUIRED accounts IDREFS # REQUIRED >
ID与IDREF • 一个元素最多只能有一个类型为ID的属性 • 一个XML文档中, 每个元素的ID属性的值必须互不相同 • ID属性值相当于对象标识 • 类型为IDREF的属性必须包含同一文档中的某个元素的ID值 • 类型为IDREFS的属性包含 ID值的列表(0 或多个, 以空格分隔). 每个ID值必须是同一文档中的某个元素的ID值 • ID与IDREF属性起着与OO和OR数据库中引用机制相同的作用, 可构造复杂的数据联系.
带有ID属性的银行DTD • 具有 ID 和 IDREF 属性类型的银行DTD <!DOCTYPE bank-2[ <!ELEMENT account (branch, balance)> <!ATTLIST account account_number ID # REQUIRED owners IDREFS # REQUIRED> <!ELEMENT customer(customer_name, customer_street, customer_city)> <!ATTLIST customer customer_id ID # REQUIRED accounts IDREFS # REQUIRED> … declarations for branch, balance, customer_name, customer_street and customer_city …]>
具有ID和IDREF属性的XML数据 <bank-2> <account account_number=“A-401” owners=“C100 C102”> <branch_name> Downtown </branch_name> <balance> 500 </balance> </account> <customer customer_id=“C100” accounts=“A-401”> <customer_name>Joe </customer_name> <customer_street> Monroe </customer_street> <customer_city> Madison</customer_city> </customer> <customer customer_id=“C102” accounts=“A-401 A-402”> <customer_name> Mary </customer_name> <customer_street> Erin </customer_street> <customer_city> Newark </customer_city> </customer> </bank-2>
DTD的局限性 • DTD源于文档格式化, 不适合数据处理应用中的类型结构定义. • 由于DTD是XML标准的一部分, 有一些数据交换格式是用DTD定义的. • 文本元素和属性没有类型系统 • 所有值都是串, 没有整数, 实数等. • 难以说明子元素的无序集合 • 在数据库中次序通常是无关紧要的(与XML源自的文档布局不同) • (A | B)* 允许说明一个无序集合, 但是不能保证A和B各只出现一次 • ID和IDREF是无类型的 • account 元素的owners属性可能包含对另一个account 的引用, 这是无意义的 • 理想情况下owners属性应该限制为引用customer 元素
XML Schema W3C XML Schema Definition Language (XSD) 1.1 Part 1: Structures W3C Working Draft 20 June 2008 W3C XML Schema Definition Language (XSD) 1.1 Part 2: Datatypes W3C Working Draft 20 June 2008 • XML Schema 是一个更精细的模式语言,可以解决DTD的缺点. 它支持定义 • 值的类型 • 例如: string, integer, decimal, date, boolean等 • 还可以对最小/最大值加以限制 • 用户定义类型 • 简单类型加限制 • 复杂类型: complexType, sequence等 • 还有许多其他特色, 包括 • 唯一性与外键约束, 继承 • 与DTD不同的是, XML Schema模式定义本身符合XML语法 • 为避免与其他标签冲突, 可用XML Schema名字空间来区别. 如 <xs:schema xmlns:xs=http://www.w3.org/2001/XMLSchema>
银行DTD的XML Schema 版本 <xs:schema xmlns:xs=http://www.w3.org/2001/XMLSchema> <xs:element name=“bank” type=“BankType”/> <xs:element name=“account”><xs:complexType> <xs:sequence> <xs:element name=“account_number” type=“xs:string”/> <xs:element name=“branch_name” type=“xs:string”/> <xs:element name=“balance” type=“xs:decimal”/> </xs:squence></xs:complexType> </xs:element> …..definitions of customer and depositor …. <xs:complexTypename=“BankType”><xs:squence> <xs:element ref=“account” minOccurs=“0” maxOccurs=“unbounded”/> <xs:element ref=“customer” minOccurs=“0” maxOccurs=“unbounded”/> <xs:element ref=“depositor” minOccurs=“0” maxOccurs=“unbounded”/> </xs:sequence> </xs:complexType> </xs:schema>
银行DTD的XML Schema 版本(续) • 选用“xs:” 是我们作出的 – 可以选用任何其他名字空间前缀 • “bank”元素具有类型 “BankType”, 它是单独定义的 • xs:complexType 在后面用来创建命名复杂类型 “BankType” • “account” 元素的类型是in-line定义的 • 可以定义子元素出现的最小和最大次数 • 缺省都为1
XML Schema的更多特色 • 用xs:attribute标签说明属性: <xs:attribute name = “account_number”/> • 置于account元素声明中 • <xs:attribute>中加入属性use = “required” 意味着必须声明的属性. • use的缺省值是"optional" • 键约束: “account_number构成根元素bank之下account元素的键" <xs:key name = “accountKey”> <xs:selector xpath = “/bank/account”/> <xs:field xpath = “account_number”/> </xs:key> • 外键约束: 从depositor 到account <xs:keyref name = “depositorAccountFKey” refer=“accountKey”> <xs:selector xpath = “/bank/depositor”/> <xs:field xpath = “account_number”/> </xs:keyref>
XML Schema vs. DTD • 允许元素中的文本受限于特定类型 • 允许创建用户定义类型 • 允许唯一性和外键约束 • 与名字空间集成, 允许文档的不同部分遵守不同模式 • 允许对类型加以限制形成特殊类型: 如最大最小值 • 利用某种形式的继承, 允许复杂类型被扩展
查询与转换 • XML应用的越来越多, 需要有效管理XML数据的工具 • 从大量XML数据中查询信息 • 在不同XML模式间转换数据 • 上述两种情况是紧密相关的, 可用同样的工具处理 • 标准XML查询/转换语言 • XPath • 由路径表达式组成的简单语言 • 是下面两种语言的构件 • XQuery • 标准XML查询语言 • XSLT • XSL的一部分 • 用于文档格式化,而非数据管理应用
XML数据的树模型 • 上述三种查询与转换语言都基于XML数据的树模型 • 一个XML文档建模成一棵树, 结点对应于元素和属性 • 元素结点可有子结点: 表示元素的属性或子元素 • 结点(除了根结点)具有单一父结点, 该父结点是一个元素结点 • 一个结点的子结点按照他们在XML文档中的次序排列 • 元素的文本内容建模成该元素的文本子结点 • 若文本内容被子元素分隔, 则一个元素可有多个文本子结点 • 如this is a<bold> wonderful </bold>book表示为三个子结点
XPath XML Path Language (XPath) 2.0 (Second Edition) W3C Recommendation 14 December 2010 (Link errors corrected 3 January 2011) • XPath 利用路径表达式来选择文档的部件 • 路径表达式是用“/”分隔开的一个定位步骤序列 • 考虑在目录层次中的文件名 • 路径表达式的结果: 能匹配指定路径的节点集合 • 例:/bank-2/customer/customer_name在 bank-2 data 上求值可返回 <customer_name>Joe</customer_name> <customer_name>Mary</customer_name> • 例: /bank-2/customer/customer_name/text( )返回客户名, 但不含外围标签
XPath (续) 起始 “/” 表示文档的根(在文档顶级标签之上的抽象根节点) 路径表达式从左至右求值 路径上任何一点的结果都是一个有序节点集合 每一步都对前一步产生的“当前”元素集合进行操作 最后一步产生的元素集合就是路径表达式的值 利用 “@”访问属性值 例:/bank-2/account/@account_number 返回account元素的account_number属性的值 IDREF属性不能自动 dereferenced (稍后详述) 选择谓词可以跟在路径中的任何一步后面, 放在[ ]中 /bank-2/account[balance > 400] 返回balance值大于400的account 元素 测试子元素存在性: /bank-2/account[balance] 返回包含balance子元素的account 元素
XPath中的函数 • XPath 提供若干函数 • 聚合函数count(exp)计算与exp匹配的结点个数 • 例:/bank-2/account[count(./customer) > 2] • 返回多于2 个客户的帐户 • 测试当前结点在兄弟序中的位置 (1, 2, ..)的函数position() • 布尔连接词and和or以及函数not()可用于谓词中 • 函数id("foo")返回具有ID类型属性并且值为foo的结点(如果有的话) • id()还可作用于引用集合上, 甚至作用于包含多个用空格分隔的引用的串上. 如IDREFS • 例如/bank-2/account/id(@owners) • 返回所有被account元素的owners属性引用的客户
XPath 的更多特色 运算符 “|” 用来实现并集 例:/bank-2/account/id(@owner) |/bank-2/loan/id(@borrower) 返回有帐户或贷款的客户 但是, “|” 不能嵌套在其他运算符内. “//” 可用于跳过多层结点 例如/bank-2//customer_name 在/bank-2元素下的任何地方找出所有customer_name元素, 不管它被包含在哪个元素当中. 无需了解完整模式也可查询数据 路径中的一步可以到达前一步生成的结点的父亲, 兄弟, 祖先及后裔, 而不仅仅到达子结点 “//”, 如上述, 是指明“所有后裔”的一种缩写形式 “..” 指明父结点 函数doc(name) 返回命名文档的根 name可以是 文件名或URL 例: doc(“bank.xml”)/bank/account collection(name)类似doc()
XQuery XQuery 1.0: An XML Query Language (Second Edition) W3C Recommendation 14 December 2010 (Link errors corrected 3 January 2011) • XQuery是XML数据的标准查询语言, 模仿SQL • 当前正在被W3C标准化中 • 教材中的描述基于该标准的January 2005草案. 最后版本可能有不同, 但主要特色很可能保持不变. • XQuery 源自Quilt, Quilt自身又是出自XPath, XQL 和XML-QL • XQuery 使用FLWOR表达式进行查询 for … let … where … order by …return … • 与SQL的比较:for SQL fromwhere SQL whereorder by SQL order by result SQL select let允许将XPath表达式的结果赋予临时变量, 用于简化表示. 在SQL中没有对应.
XQuery中的FLWOR语法 For子句使用XPath表达式, for子句中的变量即在 XPath返回的值集合上变化 多个变量时, 各变量的可取值构成笛卡儿积 例: 找出所有余额大于400的帐户, 每个结果都放入一对标签<account_number> .. </account_number> 中for $x in /bank-2/account let $acctno := $x/@account_number where $x/balance > 400 return <account_number> { $acctno } </account_number> Let子句不是必需的, 另外选择可以在XPath中完成. 上面的 查询可写成: for $x in /bank-2/account[balance>400]return <account_number> { $x/@account_number } </account_number> return子句中的项是 XML 文本, 除非括在{}中, 这时是要计算的表达式 又如: return <account account_number=“{$x/@account_number}”/> 还可用element和attribute来构造元素. 如: returnelement account{ attribute account_number {$x/@account_number}, attribute branch_name {$x/branch_name}, element balance {$x/balance}}
联接 • 联接的说明非常类似于SQL for $a in /bank/account, $c in/bank/customer, $d in /bank/depositor where $a/account_number = $d/account_number and $c/customer_name = $d/customer_name return <cust_acct> { $c $a } </cust_acct> • 同一查询也可表达为利用XPath选择: for $a in /bank/account $c in /bank/customer $d in /bank/depositor[ account_number = $a/account_number and customer_name = $c/customer_name] return <cust_acct> { $c $a } </cust_acct>
嵌套查询 FLWOR表达式可嵌套在return子句中, 以生成源文档中没有的元素嵌套结构 下列查询将数据从bank信息的平面结构转换成bank-1的嵌套结构 <bank-1> { for $c in /bank/customer return <customer> { $c/* } { for $d in /bank/depositor[customer_name = $c/customer_name], $a in /bank/account[account_number=$d/account_number] return $a } </customer> } </bank-1> $c/*表示绑定到$c的结点(序列)的所有子结点 下列查询完成类似分组聚合的功能 for $c in /bank/customer return <customer_total_balance> <customer_name>{ $c/customer_name}</customer_name> <total_balance> { fn:sum( for $d in /bank/depositor[customer_name = $c/customer_name], $a in /bank/account[account_number=$d/account_number] return $a/balance)}</total_balance>)}</total_balance> </customer_total_balance>
XQuery中的排序 order by 子句可对结果排序 例如返回按姓名排序的客户for $c in /bank/customerorder by $c/customer_name return <customer> { $c/* } </customer> 用order by $c/customer_name descending来降序排序 可以在多个嵌套层次上排序(如先按customer-name排序, 每个客户内再按account-number排序) <bank-1> {for $c in /bank/customer order by $c/customer_name return <customer> { $c/* } { for $d in /bank/depositor[customer_name=$c/customer_name], $a in /bank/account[account_number=$d/account_number] } order by $a/account_number return <account> {$a/*} </account> } </customer> } </bank-1>
函数,类型及其他特色 • XQuery提供很多内建函数 • XQuery还支持用户定义函数define function balances(xs:string $c) as xs:decimal* {for $d in /bank/depositor[customer_name = $c], $a in /bank/account[account_number = $d/account_number]return $a/balance } • 函数参数和返回值的类型声明是可选的 • decimal* 中的* 指示该类型的一个值序列 • 具有XML Schema的类型系统 • 根据需要自动进行类型转换 • 类型转换函数: 如number(str) • where子句谓词中的全称和存在量词 • some $e inpathsatisfiesP • every $e inpathsatisfiesP • XQuery还支持 If-then-else 子句 • XQJ: 提交XQuery给XML数据库系统的一个API标准
应用程序界面 • 对XML数据有两种标准的应用程序界面: • DOM (Document Object Model) • XML 数据经词法分析表示成一棵树, 元素构成节点 • 提供各种函数来遍历DOM树 • 例如: Java DOM API 提供接口Node, Element, Attribute及其方法getParentNode( ), getFirstChild( ), getNextSibling( ) getElementsByTagName( ), getAttribute( ) getData( ) (for Text node) … • 还提供修改DOM树的函数: 增删节点, 置节点值, 等等 • SAX (Simple API for XML) • 基于词法分析器模型, 用户为词法分析事件提供事件处理程序 • 词法分析事件例:元素开始, 元素结束
XML数据的存储 • XML数据可以存储成 • 非关系数据 • 平坦文件 • 存储XML很自然, 有大量工具支持 • 但有Chapter 1中讨论的所有问题 (即文件系统不具有数据隔离, 原子性, 并发, 安全等) • XML 数据库 • 以XML为基本数据模型 • 支持声明式查询(XQuery) • 复杂,代价高 • 关系数据库 • 数据必须翻译成关系形式 • 优点: 成熟的数据库系统 • 缺点: 翻译数据和查询的开销
在关系数据库中存储XML • 可选择的方式: • 串表示 • 树表示 • 映射到关系
串表示 • 小XML文档可直接存为一个元组的串字段(clob) • 大XML文档可将顶层元素的每个子元素存为一个元组中的串字段 • 用一个关系存储所有元素 • 数据库系统不知道XML文档的模式, 不能直接查询数据 • 用不同关系存储不同元素类型 • 例如 account, customer, depositor 关系 • 各有一个串值属性来存储元素 • 索引 • 将待索引的子元素/属性的值存储为关系的额外字段, 并在这些字段上建立索引 • 例如 customer_name 或者 account_number • 某些数据库系统支持函数索引, 它使用函数结果作为键值. • 例如用户定义函数返回account_number属性的值, 对此函数即可建立函数索引
树表示 bank (id:1) account (id: 5) customer (id:2) customer_name(id: 3) account_number (id: 7) • 树表示: XML数据建模为树并用下列关系存储nodes(id, type, label, value) child (child_id, parent_id) • 每个元素/属性具有一个唯一的标识符 • Type指示了元素/属性 • Label说明了元素标签名/属性名 • Value是元素/属性的文本值 • 关系child 记录树中的父子联系 • 可以在child 中增加一个额外属性position来记录子结点的顺序
树表示(续) • 好处 • 即使没有DTD 也能存储任何XML数据 • 许多XML查询可翻译成关系查询 • 缺点 • 数据被分解成许多碎片, 增加了空间开销 • 即使简单查询也需要大量联接, 速度很慢
映射到关系 • 已知模式的元素映射到关系及属性, 未知模式的元素存为串或树 • 为每个已知模式的复杂元素类型(包含属性或子元素)创建一个关系 • 增加一个id 属性存储各元素的唯一标识 • 每个元素属性对应一个串值关系属性 • 简单类型的子元素对应一个关系属性(据XML Schema类型决定属性类型) • 复杂类型的子元素映射到单独的关系(递归应用上述方法) • 增加一个ID属性 • 增加一个parent_id属性跟踪父元素 • 还可存储位置信息position (ith子结点) • 变种 • 最多只出现一次的子元素对应为父关系的属性(平坦化) • 出现多次的子元素用一个单独的表来表示 • 类似于将ER 图转换成表时对多值属性的处理
在关系系统中存储XML数据 • Publishing: 将关系数据转换成XML格式 • Shredding: 将XML数据转换成规范化关系形式存入关系数据库 • XML-enabled 数据库系统支持自动publishing和shredding • 映射机制: 例如简单表的每一行映射成一个元素, 其中每一列映射成该元素的子元素 • 某些系统利用xml数据类型来提供XML数据的native 存储 • 使用专门的内部数据结构和索引来提高效率 • 可使用XQuery