甘草轩

Never surrender to complexity
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

SQL Server 2000 XML之七种兵器

Posted on 2006-07-27 17:54  甘草轩  阅读(312)  评论(0编辑  收藏  举报
 

XML,已成近来最热门Web,它是SQL Server 2000中的重要部分。本文将合七条SQL Server 2000中最重要的XML合特性XML之七兵器。

  兵器之一:FOR XML

  在SQL Server 2000中,准的T-SQL SELECT句包括FOR XML子句,它以XML文档形式返回一个查询结果。新的FOR XML子句有三模式——RAWAUTO,和EXPLICIT个都能XML文档格式提供附加准的控制。

  下面首先介“FOR XML”的使用方法。

  了从SQL Server提取XML格式的数据,T-SQL中加入了一个FOR XML命令。查询命令中使用FOR XML命令使得查询结果以XML格式出FOR XML命令有三模式:RAWAUTOEXPLICIT1示的SQL命令访问SQL Server提供的Pubs示例数据。有Pubs数据的更多信息,MSDN明。如果我依次指定SQL命令的模式的模式之一,就可以得到各模式所支持的不同XML出。

1

SELECT store.stor_id as Id, stor_name as Name,

sale.ord_num as OrderNo,sale.qty as Qty

FROM stores store inner join

sales sale on store.stor_id = sale.stor_id

ORDER BY stor_name

FOR XML <模式>

  该查询命令所生成的果包含所有记录及其对应的商店,果以商店名称的字母升序排列。查询的最后加上了FOR XML命令以及具体的模式,比如FOR XML RAW

  理想情况下,SQL命令所生成的XML文档具有如下构:

Stores

Store Id=&single;&single; Name=&single;&single;

/Sale OrderNo=&single;&single; Qty=&single;&single;

/Store

/Stores

  下面我来看看具体的理方法。

  RAW模式

  下面是指定RAW模式时结XML文档的一个片断。

 

  查询结果集中一个记录包含唯一的元素<row>。由于我无法控制元素名字和文档构,因此这种模式不是很有用。RAW模式所生成的文档构与我所希望的不符,而且它的用途也非常有限。

  AUTO模式

  下面是指定AUTO模式时结果文档的一个片断:

 

  可以看到,<Stroe>和<Sale>两个元素是父-系,形成了我所希望的构。这种节系由查询中表的声明次序决定,后声明的表成前声明表的孩子。

  再参考1,我可以看出查询命令所指定的名决定了XML文档中的名字。根据一点,我可以控制XML文档元素、属性的名字,使得些名字符合我所要求的命名例。

  可AUTO模式能够创建出我所需要的XML文档。不它存在以下缺点:

  然可以得到构,但这种层构是线性的,即个父点只能有一个子点,反之亦然。

  通过别名指定元素名字不太方便,而且有候会影响查询命令本身的可性。

  无法在文档中同生成元素和属性。要全部是元素(通ELEMENTS关键词指定),要全部是属性(默)。 EXPLICIT模式解决了上述不足。

EXPLICIT模式

  EXPLICIT模式比较复杂,我将用另外一方法来表达1示的查询这种方法使得我完全地控制查询所生成的XML文档。首先我将介如何改用EXPLICIT模式1示的查询,然后看看这种方法如何予我们远远AUTO模式的能力。

  下面是1查询EXPLICIT模式表达的代

2

--商店数据
SELECT 1 as Tag,
NULL as Parent,
s.stor_id as [store!1!Id],
s.stor_name as [store!1!Name],
NULL as[sale!2!OrderNo],
NULL as [sale!2!Qty]
FROM stores s
UNION ALL
--
售数据
SELECT 2, 1,
s.stor_id,
s.stor_name,
sa.ord_num,
sa.qty
FROM stores s, sales sa
WHERE s.stor_id = sa.stor_id
ORDER BY [store!1!name]
FOR XML EXPLICIT

  查询初看起来有点复杂,其它只是把不同的数据集(即里的StoreSale)分解到了独立的SELECT句里,然后再用UNION ALL操作符连结成一个查询

  我之所以要把查询写成上面的形式,是让查询结果不包含XML文档所描述的数据,而且包含描述XML文档构的元数据。上述查询所生成的表称Universal表,sqlxml.dll生成XML文档需要这种格式。Universal写代的人来是透明的,但了解个表是很有意的,它将有助于代开发调试下面是Universal表的一个例子:

Tag Parent store!1!id store!1!name sale!2!orderno sale!2!qty
1 NULL 7066 Barnum&single;s NULL NULL
2 1 7066 Barnum&single;s A297650 50
2 1 7066 Barnum&single;s QA7442 375
1 NULL 8042 Bookbeat NULL NULL
2 1 8042 Bookbeat 423LL9 2215

  Universal表和EXPLICIT模式查询的元数据部分都以色表示,黑色表示数据。比较查询和表就可以找出sqlxml.dll生成XML文档所需要的元素。我来仔地分析一下它述的是什

  TagParent列是XML文档构方面的信息,我可以认为图2中的SELECT句代表了一个XML点,而TagParent指定点在文档构中的位置。如果在第二个SELECT句中指定Tag2、指定Parent1,就表示为这些数据加上了一个值为2标签,而些数据的父是那些标签为1的数据(即第一个SELECT句)。就使得我构造出<Store>和<Sale>之的父-系,而且正如你可能猜想到的,它使得我可以生成任意合法的XML文档构。注意第一个SELECT命令的parent置成了NULL表示<Store>元素于最顶层的位置。

  以黑色表示的数据将成为节点的属性或元素,例如,Store_ID就通列名提供了方面的信息。列名字中的“!”是分隔符,共可分成四(四个参数),其中第四个参数是可的。些参数描述的是:

  第一个参数描述列所属元素的名字,在里是<Store>元素。

  第二个是标签编号,它指定了列信息在XML构中所位置。

  第三个参数指定XML文档内的属性或元素名字。在里名字指定id

  数据列默参数2所指定点的属性,即id将成Store点的属性。如果要指定id是<Store>的一个子元素,我可以使用第四个可的参数,个参数的一个作用就是该项指定元素,例如store!1!id!element

  由于使用了UNION ALL操作符来连结SELECT句,了保SQL查询的合法性,所有SELECT句的选择结果必具有相同数量的列。我使用NULL关键词SELECT句,从而避免了重数据。

  通EXPLICIT模式查询所生成的XML文档和通AUTO模式生成的完全相同,那么为EXPLICIT模式查询呢?

  假设现在有人要求在XML文档中包含商店的打折信息。Pubs数据,我得知个商店都可以有0n内的折扣率。因此,一合理的方法是在<Store>元素下面加上子元素<Discount>,这样就得到如下XML文档构:

STORES
STORE Id=&single;&single; Name=&single;&single;
DISCOUNT Type=&single;&single; LowQty=&single;&single; HighQty=&single;&single;
AMOUNT></AMOUNT
/DISCOUNT
SALE OrdNo=&single;&single; Qty=&single;&single;
/SALE
/STORE
/STORES

  里的改包括:

  要在<Sale>元素所在的次增加一个XML元素<Discount>,即<Discount>是<Stroe>的子元素。

  Amount嵌套在<Discount>里面,但不应该是<Discount>元素的属性。

  在AUTO模式中是不可能实现这些改的。

  下面是个新XML文档的EXPLICIT模式查询

2A

SELECT 1 as Tag, NULL as Parent,
s.stor_id as [Store!1!id],
s.stor_name as [Store!1!name],
NULL as [Sale!2!orderno],
NULL as [Sale!2!1ty],
NULL as [Discount!3!type],
NULL as [Discount!3!lowqty],
NULL as [Discount!3!highqty],
NULL as [Discount!3!amount!element]
FROM stores s
UNION ALL
SELECT 2, 1,
s.stor_id,
s.stor_name,
sa.ord_num,
sa.qty,
NULL,
NULL,
NULL,
NULL
FROM stores s, sales sa
WHERE s.stor_id = sa.stor_id
UNION ALL
SELECT 3, 1,
NULL,
s.stor_name,
NULL,
NULL,
d.discounttype,
d.lowqty,
d.highqty,
d.discount
FROM stores s, discounts d
WHERE s.stor_id = d.stor_id
ORDER BY [store!1!name]
For XML EXPLICIT

  2A示的EXPLICIT模式查询,我们对图2查询进行了如下修改:

  增加了第三个子查询提取折扣数据,通Tag列声明些数据的标签值为3

  通指定Parent1将折扣数据置成<Store>元素的子元素。

  注意在第三个SELECT查询中我只包含了那些必需的列,并用NULL足空列。个子查询包含store_name列,Discount元素并不要用到个列,但如果把个列也NULL则结Universal表将不会按照解析器所要求的那点升序排序(不妨自己一下看看)。Universal表的排序列也可以用Tag列替代。

  为维Universal表的完整性,第一、二两个SELECT句也用NULL足以反映折扣数据增加的列。

  指定新折扣列的元数据修改了第一个SELECT句。

  在第四个参数中声明element指定AmountDiscount的一个元素(element是可在第四个参数中声明的多个指令之一)。

  下面XML文档只能用EXPLICIT模式生成:

 

  XML文档中不会示出NULL数据,如折扣lowqtyhighqty

  看来上面的介,大家可能已经对FOR XML法有所了解。通FOR XML 在能Query Analyzer 中直接返回一个XML格式的数据或者通其他多化表方式将XML格式的数据示出来,比如可以将数据示在浏览器上。下面个例子就使用FOR XMLADO将数据出到浏览器的例子。

Dim adoConn
Set adoConn = Server.CreateObject("ADODB.Connection")

Dim sConn
sConn = "Provider=SQLOLEDB;Data Source=192.168.0.160;Initial Catalog=Northwind;User ID=SA;Password=;"
adoConn.ConnectionString = sConn
adoConn.CursorLocation = adUseClient
adoConn.Open

Dim adoCmd
Set adoCmd = Server.CreateObject("ADODB.Command")
Set adoCmd.ActiveConnection = adoConn

Dim sQuery
FOR XML查询。具体的法在以后的章中将详细

sQuery = "
ROOT xmlns:sql='urn:schemas-microsoft-com:xml-sql'><sql:querySELECT * FROM PRODUCTS ORDER BY PRODUCTNAME FOR XML AUTO/sql:query></ROOT"

建立ADODB Stream 象,ADODB Stream 象需要ADO2.5以上版本支持,它可以将记录转换为数据流。
Dim adoStreamQuery
Set adoStreamQuery = Server.CreateObject("ADODB.Stream")
adoStreamQuery.Open
adoStreamQuery.WriteText sQuery, adWriteChar
adoStreamQuery.Position = 0
adoCmd.CommandStream = adoStreamQuery
adoCmd.Dialect = "{5D531CB2-E6Ed-11D2-B252-00C04F681B71}"

Response.write "Pushing XML to client for processing " & "BR/"

adoCmd.Properties("Output Stream") = Response
XML格式的文本

Response.write "
XML ID=MyDataIsle"
adoCmd.Execute , , adExecuteStream
Response.write "
/XML"

IEXML解析器,使用DOM方法将XML的文本转换为HTML
SCRIPT language="VBScript" For="window" Event="onload"

Dim xmlDoc
Set xmlDoc = MyDataIsle.XMLDocument
xmlDoc.resolveExternals=false
xmlDoc.async=false

Dim root, child
Set root = xmlDoc.documentElement

For each child in root.childNodes
dim OutputXML
OutputXML = document.all("log").innerHTML
document.all("log").innerHTML = OutputXML & "
LI" & child.getAttribute("ProductName") & "/LI
"
Next

/SCRIPT

 兵器之二:XPath

  W3C 1999 10 8 日提出的 XPath 范,它是一基于XML查询语言,它能在XML理数据。SQL Server 2000 实现的是该规范的子集。它把tableviewsXML件,并把columnsXML属性。SQL Server 2000XML支持IIS使用URL或者模板的方式提交到SQL ServerXpath查询,并返回XML果。

  支持的功能

  下表 SQL Server 2000 实现 XPath 言的功能。

功能

attributechildparent self

包括连续谓词和嵌套谓词在内的布尔值谓词

 

所有系运算符

=, !=, , =, , =

运算符

+, -, *, div

转换函数

number()string()Boolean()

运算符

AND, OR

函数

true()false()not()

XPath

 


  不支持的功能

  下表 SQL Server 2000 中没有实现 XPath 言的功能。

功能

ancestorancestor-or-selfdescendantdescendant-or-self (//)followingfollowing-siblingnamespaceprecedingpreceding-sibling

值谓词

 

运算符

mod

点函数

ancestorancestor-or-selfdescendantdescendant-or-self (//)followingfollowing-siblingnamespaceprecedingpreceding-sibling

字符串函数

string()concat()starts-with()contains()substring-before()substring-after()substring()string-length()normalize()translate()

函数

lang()

数字函数

sum()floor()ceiling()round()

Union 运算符

|

  XPath 查询是以表达式的形式指定的。位置路径是一常用表达式,用以选择于上下文点的点集。位置路径表达式的求值结果是点集。

XML 文档
root
  
order productid="Prod-28" unitprice="45.6" quantity="15"
  
discount0.25/discount
  
/order
  
order productid="Prod-39" unitprice="18" quantity="21"

  
discount0.25/discount
  
/order

  
order productid="Prod-46" unitprice="12" quantity="2"
  
discount0.25/discount

  
/order
/root

  下面是查询该XML 文档的XPath位置路径表达式,它的含是返回根点下所有<ROOT>子元素下的ProductID属性的属性值为 "prod-39" order 元素。

 

  位置路径的

  可以分为绝对位置路径和相位置路径。


  绝对位置路径以文档的根始,由斜杠 (/) 成,后面可以是相位置路径。斜杠 (/) 定文档的根点。


  相位置路径以文档的上下文点(Context始,由斜杠 (/) 所分的一个或多个位置步骤序列成。步骤定相于上下文点的点集。初始步骤序列定相于上下点的点集。点集中的点都用作后续步骤的上下文点。由后续步骤标识点集接在一起。例如,child::Order/child::OrderDetail 定上下文点的<order 子元素的 orderdetail 子元素。

  位置步骤 绝对或相)位置路径由包含下面三部分的位置步骤组成:

  

  指定位置步骤选定的点与上下文点之树关系。SQL Server 2000 支持 parentchildattribute self

  如果在位置路径中指定 child 查询选定的所有点都将是上下文点的子点。
比如查询从当前的上下文点中定所有 Order点的子,可以使用 child:: Order

  如果指定 parent 定的点将是上下文点的父点。
比如查询从当前的上下文点中定所有 Order点的父,可以使用 parent:: Order

  如果指定 attribute 定的点是上下文点的属性。
比如查询从当前的上下文点中定所有 Order点的属性,可以使用 attribute:: Order

  测试

  测试指定位置步骤选定的型。childparentattribute self)都具有主要型。 attribute ,主要型是 attribute>。 parentchild self ,主要型是 element>。

  例如,如果位置路径指定 child::Order定上下文点的 Order 子元素。因 child element 其主要型,而且如果Order element 点,则节测试Order TRUE

  选择谓词(零个或多个)

  谓词围绕轴筛选节点集。在 XPath 表达式中指定选择谓词与在 SELECT 句中指定 WHERE 子句相似。谓词在括号中指定。用在选择谓词中指定的测试对节测试返回的筛选于要筛选点集中的点,在对谓词表达式取值时将此点作上下文点,将点集中的点数作上下文大小。如果谓词表达式点取值为 TRUE点将包括在最后所得到的点集中。

  例如:
  1. Child::Order [attribute::ProductID="Prod-39"] 表示从当前的上下文点中ProductID属性值为Prod-39的所有 order>子点。

  2. Child::Order [child:: Discount] 表示从当前的上下文点中定包含一个或多个 Discount 点的所有 Order 点。

  3. Child::Order [not(child:: Discount)] 表示从当前的上下文点中定不包含 Discount 点的所有 Order 点。

  位置步骤

  是用两个冒号 (::) 名和测试,后面是分放在方括号中的零个或多个表达式。

  例如,在 XPath 表达式(位置路径)child::Order[attribute::ProductID="prod-39"]中,定上下文点的所有 order 子元素。然后将谓词中的测试应用于点集,将只返回 ProductID属性的属性值为 "prod-39" order 元素点。

  

  Sqlservr2000支持下面的位置路径:
  attribute::可以 @

  比如:[attribute::ProductID="Prod-39"] 可以写成 [@ProductID =" Prod-39"]

  child::可以在位置步骤中省略。
  比如:位置路径child::ROOT/child::Orde可以写成 ROOT /Order

  self::node() 一个句点 (.),而 parent::node() 略两个句点 (..)

  所以 /child::ROOT/child::Order[attribute::ProductID="prod-39"]也可以写成 /ROOT/Order[@ProductID="prod-39"]