隨筆 - 3, 文章 - 152, 評(píng)論 - 17, 引用 - 0
          數(shù)據(jù)加載中……

          SQL Server 2000 XML之七種兵器

          XML,已成為近來(lái)最熱門的Web技術(shù),它是SQL Server 2000中的重要部分。本文將綜合七條SQL Server 2000中最重要的XML綜合特性組成XML之七種兵器。

            兵器之一:FOR XML

            在SQL Server 2000中,標(biāo)準(zhǔn)的T-SQL SELECT語(yǔ)句包括FOR XML子句,它以XML文檔形式返回一個(gè)查詢結(jié)果。新的FOR XML子句有三種模式——RAW,AUTO,和EXPLICIT,每個(gè)都能對(duì)XML文檔格式提供附加標(biāo)準(zhǔn)的控制。

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

            為了從SQL Server提取XML格式的數(shù)據(jù),T-SQL中加入了一個(gè)FOR XML命令。在查詢命令中使用FOR XML命令使得查詢結(jié)果以XML格式出現(xiàn)。FOR XML命令有三種模式:RAW,AUTO和EXPLICIT。圖1所顯示的SQL命令訪問(wèn)SQL Server提供的Pubs示例數(shù)據(jù)庫(kù)。有關(guān)Pubs數(shù)據(jù)庫(kù)的更多信息,請(qǐng)參見(jiàn)MSDN說(shuō)明。如果我們依次指定該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 <模式>

            該查詢命令所生成的結(jié)果包含所有銷售記錄及其對(duì)應(yīng)的商店,結(jié)果以商店名稱的字母升序排列。查詢的最后加上了FOR XML命令以及具體的模式,比如FOR XML RAW。

            理想情況下,SQL命令所生成的XML文檔應(yīng)具有如下結(jié)構(gòu):

          <Stores>

          <Store Id=&single;&single; Name=&single;&single;>

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

          </Store>

          </Stores>

            下面我們來(lái)看看具體的處理方法。

            RAW模式

            下面是指定RAW模式時(shí)結(jié)果XML文檔的一個(gè)片斷。

            查詢結(jié)果集中每一個(gè)記錄包含唯一的元素<row>。由于我們無(wú)法控制元素名字和文檔結(jié)構(gòu),因此這種模式不是很有用。RAW模式所生成的文檔結(jié)構(gòu)與我們所希望的不符,而且它的用途也非常有限。

            AUTO模式

            下面是指定AUTO模式時(shí)結(jié)果文檔的一個(gè)片斷:

            可以看到,<Stroe>和<Sale>兩個(gè)元素是父-子關(guān)系,形成了我們所希望的層次結(jié)構(gòu)。這種節(jié)點(diǎn)關(guān)系由查詢中表的聲明次序決定,后聲明的表成為前聲明表的孩子。

            再參考圖1,我們可以看出查詢命令所指定的別名決定了XML文檔中的名字。根據(jù)這一點(diǎn),我們可以控制XML文檔元素、屬性的名字,使得這些名字符合我們所要求的命名慣例。

            可見(jiàn)AUTO模式能夠創(chuàng)建出我們所需要的XML文檔。不過(guò)它存在以下缺點(diǎn):

            雖然可以得到層次結(jié)構(gòu),但這種層次結(jié)構(gòu)是線性的,即每個(gè)父節(jié)點(diǎn)只能有一個(gè)子節(jié)點(diǎn),反之亦然。

            通過(guò)別名指定元素名字不太方便,而且有時(shí)候會(huì)影響查詢命令本身的可讀性。

            無(wú)法在文檔中同時(shí)生成元素和屬性。要么全部是元素(通過(guò)ELEMENTS關(guān)鍵詞指定),要么全部是屬性(默認(rèn))。 EXPLICIT模式解決了上述不足。


           EXPLICIT模式

            EXPLICIT模式比較復(fù)雜,我們將用另外一種方法來(lái)表達(dá)圖1所顯示的查詢。這種方法使得我們能夠完全地控制查詢所生成的XML文檔。首先我們將介紹如何改用EXPLICIT模式編寫圖1所顯示的查詢,然后看看這種方法如何賦予我們遠(yuǎn)遠(yuǎn)超過(guò)AUTO模式的能力。

            下面是圖1查詢用EXPLICIT模式表達(dá)的代碼:

          【圖2 】

          --商店數(shù)據(jù)
          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
          -- 銷售數(shù)據(jù)
          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

            這個(gè)查詢初看起來(lái)有點(diǎn)復(fù)雜,其實(shí)它只是把不同的數(shù)據(jù)集(即這里的Store和Sale)分解到了獨(dú)立的SELECT語(yǔ)句里,然后再用UNION ALL操作符連結(jié)成一個(gè)查詢。

            我們之所以要把查詢寫成上面的形式,是為了讓查詢結(jié)果不僅包含XML文檔所描述的數(shù)據(jù),而且還包含描述XML文檔結(jié)構(gòu)的元數(shù)據(jù)。上述查詢所生成的表稱為Universal表,sqlxml.dll生成XML文檔時(shí)需要這種格式。Universal表對(duì)于編寫代碼的人來(lái)說(shuō)是透明的,但了解這個(gè)表還是很有意義的,它將有助于代碼的開(kāi)發(fā)和調(diào)試。下面是Universal表的一個(gè)例子:

          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模式查詢的元數(shù)據(jù)部分都以紅色表示,黑色表示數(shù)據(jù)。比較查詢和表就可以找出sqlxml.dll生成XML文檔所需要的元素。我們來(lái)仔細(xì)地分析一下它們描述的是什么。

            Tag和Parent列是XML文檔層次結(jié)構(gòu)方面的信息,我們可以認(rèn)為圖2中的每個(gè)SELECT語(yǔ)句代表了一個(gè)XML節(jié)點(diǎn),而Tag和Parent列讓我們指定節(jié)點(diǎn)在文檔層次結(jié)構(gòu)中的位置。如果在第二個(gè)SELECT語(yǔ)句中指定Tag為2、指定Parent為1,就表示為這些數(shù)據(jù)加上了一個(gè)值為2的標(biāo)簽,而這些數(shù)據(jù)的父親是那些標(biāo)簽為1的數(shù)據(jù)(即第一個(gè)SELECT語(yǔ)句)。這就使得我們能夠構(gòu)造出<Store>和<Sale>之間的父-子關(guān)系,而且正如你可能猜想到的,它使得我們可以生成任意合法的XML文檔結(jié)構(gòu)。注意第一個(gè)SELECT命令的parent列設(shè)置成了NULL,這表示<Store>元素處于最頂層的位置。

            以黑色表示的數(shù)據(jù)將成為節(jié)點(diǎn)的屬性或元素,例如,Store_ID就通過(guò)列名提供了這方面的信息。列名字中的“!”是分隔符,總共可分成四項(xiàng)(四個(gè)參數(shù)),其中第四個(gè)參數(shù)是可選的。這些參數(shù)描述的是:

            第一個(gè)參數(shù)描述該列所屬元素的名字,在這里是<Store>元素。

            第二個(gè)是標(biāo)簽編號(hào),它指定了該列信息在XML樹(shù)形結(jié)構(gòu)中所處位置。

            第三個(gè)參數(shù)指定XML文檔內(nèi)的屬性或元素名字。在這里名字指定為id。

            數(shù)據(jù)列默認(rèn)被創(chuàng)建為參數(shù)2所指定節(jié)點(diǎn)的屬性,即id將成為<Store>節(jié)點(diǎn)的屬性。如果要指定id是<Store>的一個(gè)子元素,我們可以使用第四個(gè)可選的參數(shù),這個(gè)參數(shù)的一個(gè)作用就是讓我們把該項(xiàng)指定為元素,例如store!1!id!element。

            由于使用了UNION ALL操作符來(lái)連結(jié)SELECT語(yǔ)句,為了保證SQL查詢的合法性,所有SELECT語(yǔ)句的選擇結(jié)果必須具有相同數(shù)量的列。我們使用NULL關(guān)鍵詞來(lái)補(bǔ)足SELECT語(yǔ)句,從而避免了重復(fù)數(shù)據(jù)。

            通過(guò)EXPLICIT模式查詢所生成的XML文檔和通過(guò)AUTO模式生成的完全相同,那么為什么要?jiǎng)?chuàng)建EXPLICIT模式查詢呢?

            假設(shè)現(xiàn)在有人要求在XML文檔中包含商店的打折信息。查看Pubs數(shù)據(jù)庫(kù),我們得知每個(gè)商店都可以有0到n范圍內(nèi)的折扣率。因此,一種合理的方法是在<Store>元素下面加上子元素<Discount>,這樣我們就得到如下XML文檔結(jié)構(gòu):

          <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>

            這里的改動(dòng)包括:

            要在<Sale>元素所在的層次增加一個(gè)XML元素<Discount>,即<Discount>是<Stroe>的子元素。

            Amount嵌套在<Discount>里面,但不應(yīng)該是<Discount>元素的屬性。

            在AUTO模式中是不可能實(shí)現(xiàn)這些改動(dòng)的。

            下面是創(chuàng)建這個(gè)新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

            為了創(chuàng)建圖2A所顯示的EXPLICIT模式查詢,我們對(duì)圖2的查詢進(jìn)行了如下修改:

            增加了第三個(gè)子查詢提取折扣數(shù)據(jù),通過(guò)Tag列聲明這些數(shù)據(jù)的標(biāo)簽值為3。

            通過(guò)指定Parent列為1將折扣數(shù)據(jù)設(shè)置成<Store>元素的子元素。

            注意在第三個(gè)SELECT子查詢中我們只包含了那些必需的列,并用NULL補(bǔ)足空列。這個(gè)子查詢包含store_name列,雖然Discount元素并不要用到這個(gè)列,但如果把這個(gè)列也設(shè)置為NULL,則結(jié)果Universal表將不會(huì)按照解析器所要求的那樣以節(jié)點(diǎn)升序排序(不妨自己試一下看看)。Universal表的排序列也可以用Tag列替代。

            為維持結(jié)果Universal表的完整性,第一、二兩個(gè)SELECT語(yǔ)句也用NULL補(bǔ)足以反映為折扣數(shù)據(jù)增加的列。

            為指定新折扣列的元數(shù)據(jù)修改了第一個(gè)SELECT語(yǔ)句。

            通過(guò)在第四個(gè)參數(shù)中聲明element指定Amount列為Discount的一個(gè)元素(element是可在第四個(gè)參數(shù)中聲明的多個(gè)指令之一)。

            下面這個(gè)XML文檔只能用EXPLICIT模式生成:

            結(jié)果XML文檔中不會(huì)顯示出NULL數(shù)據(jù),如折扣lowqty和highqty。

            看來(lái)上面的介紹,大家可能已經(jīng)對(duì)FOR XML的語(yǔ)法有所了解。通過(guò)FOR XML 我們?cè)谀軌蛟赒uery Analyzer 中直接返回一個(gè)XML格式的數(shù)據(jù)或者通過(guò)其他多樣化表現(xiàn)方式將XML格式的數(shù)據(jù)顯示出來(lái),比如可以將數(shù)據(jù)顯示在瀏覽器上。下面這個(gè)例子就使用FOR XML和ADO將數(shù)據(jù)輸出到瀏覽器的例子。

          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的查詢。具體的語(yǔ)法在以后的章節(jié)中將詳細(xì)介紹。
          sQuery = "<ROOT xmlns:sql='urn:schemas-microsoft-com:xml-sql'><sql:query>SELECT * FROM PRODUCTS ORDER BY PRODUCTNAME FOR XML AUTO</sql:query></ROOT>"

          ‘建立ADODB Stream 對(duì)象,ADODB Stream 對(duì)象需要ADO2.5以上版本支持,它可以將記錄集轉(zhuǎn)換為數(shù)據(jù)流。
          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>"

          ‘通過(guò)IE的XML解析器,使用DOM方法將XML的文本轉(zhuǎn)換為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>

           EXPLICIT模式

            EXPLICIT模式比較復(fù)雜,我們將用另外一種方法來(lái)表達(dá)圖1所顯示的查詢。這種方法使得我們能夠完全地控制查詢所生成的XML文檔。首先我們將介紹如何改用EXPLICIT模式編寫圖1所顯示的查詢,然后看看這種方法如何賦予我們遠(yuǎn)遠(yuǎn)超過(guò)AUTO模式的能力。

            下面是圖1查詢用EXPLICIT模式表達(dá)的代碼:

          【圖2 】

          --商店數(shù)據(jù)
          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
          -- 銷售數(shù)據(jù)
          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

            這個(gè)查詢初看起來(lái)有點(diǎn)復(fù)雜,其實(shí)它只是把不同的數(shù)據(jù)集(即這里的Store和Sale)分解到了獨(dú)立的SELECT語(yǔ)句里,然后再用UNION ALL操作符連結(jié)成一個(gè)查詢。

            我們之所以要把查詢寫成上面的形式,是為了讓查詢結(jié)果不僅包含XML文檔所描述的數(shù)據(jù),而且還包含描述XML文檔結(jié)構(gòu)的元數(shù)據(jù)。上述查詢所生成的表稱為Universal表,sqlxml.dll生成XML文檔時(shí)需要這種格式。Universal表對(duì)于編寫代碼的人來(lái)說(shuō)是透明的,但了解這個(gè)表還是很有意義的,它將有助于代碼的開(kāi)發(fā)和調(diào)試。下面是Universal表的一個(gè)例子:

          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模式查詢的元數(shù)據(jù)部分都以紅色表示,黑色表示數(shù)據(jù)。比較查詢和表就可以找出sqlxml.dll生成XML文檔所需要的元素。我們來(lái)仔細(xì)地分析一下它們描述的是什么。

            Tag和Parent列是XML文檔層次結(jié)構(gòu)方面的信息,我們可以認(rèn)為圖2中的每個(gè)SELECT語(yǔ)句代表了一個(gè)XML節(jié)點(diǎn),而Tag和Parent列讓我們指定節(jié)點(diǎn)在文檔層次結(jié)構(gòu)中的位置。如果在第二個(gè)SELECT語(yǔ)句中指定Tag為2、指定Parent為1,就表示為這些數(shù)據(jù)加上了一個(gè)值為2的標(biāo)簽,而這些數(shù)據(jù)的父親是那些標(biāo)簽為1的數(shù)據(jù)(即第一個(gè)SELECT語(yǔ)句)。這就使得我們能夠構(gòu)造出<Store>和<Sale>之間的父-子關(guān)系,而且正如你可能猜想到的,它使得我們可以生成任意合法的XML文檔結(jié)構(gòu)。注意第一個(gè)SELECT命令的parent列設(shè)置成了NULL,這表示<Store>元素處于最頂層的位置。

            以黑色表示的數(shù)據(jù)將成為節(jié)點(diǎn)的屬性或元素,例如,Store_ID就通過(guò)列名提供了這方面的信息。列名字中的“!”是分隔符,總共可分成四項(xiàng)(四個(gè)參數(shù)),其中第四個(gè)參數(shù)是可選的。這些參數(shù)描述的是:

            第一個(gè)參數(shù)描述該列所屬元素的名字,在這里是<Store>元素。

            第二個(gè)是標(biāo)簽編號(hào),它指定了該列信息在XML樹(shù)形結(jié)構(gòu)中所處位置。

            第三個(gè)參數(shù)指定XML文檔內(nèi)的屬性或元素名字。在這里名字指定為id。

            數(shù)據(jù)列默認(rèn)被創(chuàng)建為參數(shù)2所指定節(jié)點(diǎn)的屬性,即id將成為<Store>節(jié)點(diǎn)的屬性。如果要指定id是<Store>的一個(gè)子元素,我們可以使用第四個(gè)可選的參數(shù),這個(gè)參數(shù)的一個(gè)作用就是讓我們把該項(xiàng)指定為元素,例如store!1!id!element。

            由于使用了UNION ALL操作符來(lái)連結(jié)SELECT語(yǔ)句,為了保證SQL查詢的合法性,所有SELECT語(yǔ)句的選擇結(jié)果必須具有相同數(shù)量的列。我們使用NULL關(guān)鍵詞來(lái)補(bǔ)足SELECT語(yǔ)句,從而避免了重復(fù)數(shù)據(jù)。

            通過(guò)EXPLICIT模式查詢所生成的XML文檔和通過(guò)AUTO模式生成的完全相同,那么為什么要?jiǎng)?chuàng)建EXPLICIT模式查詢呢?

            假設(shè)現(xiàn)在有人要求在XML文檔中包含商店的打折信息。查看Pubs數(shù)據(jù)庫(kù),我們得知每個(gè)商店都可以有0到n范圍內(nèi)的折扣率。因此,一種合理的方法是在<Store>元素下面加上子元素<Discount>,這樣我們就得到如下XML文檔結(jié)構(gòu):

          <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>

            這里的改動(dòng)包括:

            要在<Sale>元素所在的層次增加一個(gè)XML元素<Discount>,即<Discount>是<Stroe>的子元素。

            Amount嵌套在<Discount>里面,但不應(yīng)該是<Discount>元素的屬性。

            在AUTO模式中是不可能實(shí)現(xiàn)這些改動(dòng)的。

            下面是創(chuàng)建這個(gè)新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

            為了創(chuàng)建圖2A所顯示的EXPLICIT模式查詢,我們對(duì)圖2的查詢進(jìn)行了如下修改:

            增加了第三個(gè)子查詢提取折扣數(shù)據(jù),通過(guò)Tag列聲明這些數(shù)據(jù)的標(biāo)簽值為3。

            通過(guò)指定Parent列為1將折扣數(shù)據(jù)設(shè)置成<Store>元素的子元素。

            注意在第三個(gè)SELECT子查詢中我們只包含了那些必需的列,并用NULL補(bǔ)足空列。這個(gè)子查詢包含store_name列,雖然Discount元素并不要用到這個(gè)列,但如果把這個(gè)列也設(shè)置為NULL,則結(jié)果Universal表將不會(huì)按照解析器所要求的那樣以節(jié)點(diǎn)升序排序(不妨自己試一下看看)。Universal表的排序列也可以用Tag列替代。

            為維持結(jié)果Universal表的完整性,第一、二兩個(gè)SELECT語(yǔ)句也用NULL補(bǔ)足以反映為折扣數(shù)據(jù)增加的列。

            為指定新折扣列的元數(shù)據(jù)修改了第一個(gè)SELECT語(yǔ)句。

            通過(guò)在第四個(gè)參數(shù)中聲明element指定Amount列為Discount的一個(gè)元素(element是可在第四個(gè)參數(shù)中聲明的多個(gè)指令之一)。

            下面這個(gè)XML文檔只能用EXPLICIT模式生成:

            結(jié)果XML文檔中不會(huì)顯示出NULL數(shù)據(jù),如折扣lowqty和highqty。

            看來(lái)上面的介紹,大家可能已經(jīng)對(duì)FOR XML的語(yǔ)法有所了解。通過(guò)FOR XML 我們?cè)谀軌蛟赒uery Analyzer 中直接返回一個(gè)XML格式的數(shù)據(jù)或者通過(guò)其他多樣化表現(xiàn)方式將XML格式的數(shù)據(jù)顯示出來(lái),比如可以將數(shù)據(jù)顯示在瀏覽器上。下面這個(gè)例子就使用FOR XML和ADO將數(shù)據(jù)輸出到瀏覽器的例子。

          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的查詢。具體的語(yǔ)法在以后的章節(jié)中將詳細(xì)介紹。
          sQuery = "<ROOT xmlns:sql='urn:schemas-microsoft-com:xml-sql'><sql:query>SELECT * FROM PRODUCTS ORDER BY PRODUCTNAME FOR XML AUTO</sql:query></ROOT>"

          ‘建立ADODB Stream 對(duì)象,ADODB Stream 對(duì)象需要ADO2.5以上版本支持,它可以將記錄集轉(zhuǎn)換為數(shù)據(jù)流。
          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>"

          ‘通過(guò)IE的XML解析器,使用DOM方法將XML的文本轉(zhuǎn)換為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>

           EXPLICIT模式

            EXPLICIT模式比較復(fù)雜,我們將用另外一種方法來(lái)表達(dá)圖1所顯示的查詢。這種方法使得我們能夠完全地控制查詢所生成的XML文檔。首先我們將介紹如何改用EXPLICIT模式編寫圖1所顯示的查詢,然后看看這種方法如何賦予我們遠(yuǎn)遠(yuǎn)超過(guò)AUTO模式的能力。

            下面是圖1查詢用EXPLICIT模式表達(dá)的代碼:

          【圖2 】

          --商店數(shù)據(jù)
          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
          -- 銷售數(shù)據(jù)
          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

            這個(gè)查詢初看起來(lái)有點(diǎn)復(fù)雜,其實(shí)它只是把不同的數(shù)據(jù)集(即這里的Store和Sale)分解到了獨(dú)立的SELECT語(yǔ)句里,然后再用UNION ALL操作符連結(jié)成一個(gè)查詢。

            我們之所以要把查詢寫成上面的形式,是為了讓查詢結(jié)果不僅包含XML文檔所描述的數(shù)據(jù),而且還包含描述XML文檔結(jié)構(gòu)的元數(shù)據(jù)。上述查詢所生成的表稱為Universal表,sqlxml.dll生成XML文檔時(shí)需要這種格式。Universal表對(duì)于編寫代碼的人來(lái)說(shuō)是透明的,但了解這個(gè)表還是很有意義的,它將有助于代碼的開(kāi)發(fā)和調(diào)試。下面是Universal表的一個(gè)例子:

          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模式查詢的元數(shù)據(jù)部分都以紅色表示,黑色表示數(shù)據(jù)。比較查詢和表就可以找出sqlxml.dll生成XML文檔所需要的元素。我們來(lái)仔細(xì)地分析一下它們描述的是什么。

            Tag和Parent列是XML文檔層次結(jié)構(gòu)方面的信息,我們可以認(rèn)為圖2中的每個(gè)SELECT語(yǔ)句代表了一個(gè)XML節(jié)點(diǎn),而Tag和Parent列讓我們指定節(jié)點(diǎn)在文檔層次結(jié)構(gòu)中的位置。如果在第二個(gè)SELECT語(yǔ)句中指定Tag為2、指定Parent為1,就表示為這些數(shù)據(jù)加上了一個(gè)值為2的標(biāo)簽,而這些數(shù)據(jù)的父親是那些標(biāo)簽為1的數(shù)據(jù)(即第一個(gè)SELECT語(yǔ)句)。這就使得我們能夠構(gòu)造出<Store>和<Sale>之間的父-子關(guān)系,而且正如你可能猜想到的,它使得我們可以生成任意合法的XML文檔結(jié)構(gòu)。注意第一個(gè)SELECT命令的parent列設(shè)置成了NULL,這表示<Store>元素處于最頂層的位置。

            以黑色表示的數(shù)據(jù)將成為節(jié)點(diǎn)的屬性或元素,例如,Store_ID就通過(guò)列名提供了這方面的信息。列名字中的“!”是分隔符,總共可分成四項(xiàng)(四個(gè)參數(shù)),其中第四個(gè)參數(shù)是可選的。這些參數(shù)描述的是:

            第一個(gè)參數(shù)描述該列所屬元素的名字,在這里是<Store>元素。

            第二個(gè)是標(biāo)簽編號(hào),它指定了該列信息在XML樹(shù)形結(jié)構(gòu)中所處位置。

            第三個(gè)參數(shù)指定XML文檔內(nèi)的屬性或元素名字。在這里名字指定為id。

            數(shù)據(jù)列默認(rèn)被創(chuàng)建為參數(shù)2所指定節(jié)點(diǎn)的屬性,即id將成為<Store>節(jié)點(diǎn)的屬性。如果要指定id是<Store>的一個(gè)子元素,我們可以使用第四個(gè)可選的參數(shù),這個(gè)參數(shù)的一個(gè)作用就是讓我們把該項(xiàng)指定為元素,例如store!1!id!element。

            由于使用了UNION ALL操作符來(lái)連結(jié)SELECT語(yǔ)句,為了保證SQL查詢的合法性,所有SELECT語(yǔ)句的選擇結(jié)果必須具有相同數(shù)量的列。我們使用NULL關(guān)鍵詞來(lái)補(bǔ)足SELECT語(yǔ)句,從而避免了重復(fù)數(shù)據(jù)。

            通過(guò)EXPLICIT模式查詢所生成的XML文檔和通過(guò)AUTO模式生成的完全相同,那么為什么要?jiǎng)?chuàng)建EXPLICIT模式查詢呢?

            假設(shè)現(xiàn)在有人要求在XML文檔中包含商店的打折信息。查看Pubs數(shù)據(jù)庫(kù),我們得知每個(gè)商店都可以有0到n范圍內(nèi)的折扣率。因此,一種合理的方法是在<Store>元素下面加上子元素<Discount>,這樣我們就得到如下XML文檔結(jié)構(gòu):

          <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>

            這里的改動(dòng)包括:

            要在<Sale>元素所在的層次增加一個(gè)XML元素<Discount>,即<Discount>是<Stroe>的子元素。

            Amount嵌套在<Discount>里面,但不應(yīng)該是<Discount>元素的屬性。

            在AUTO模式中是不可能實(shí)現(xiàn)這些改動(dòng)的。

            下面是創(chuàng)建這個(gè)新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

            為了創(chuàng)建圖2A所顯示的EXPLICIT模式查詢,我們對(duì)圖2的查詢進(jìn)行了如下修改:

            增加了第三個(gè)子查詢提取折扣數(shù)據(jù),通過(guò)Tag列聲明這些數(shù)據(jù)的標(biāo)簽值為3。

            通過(guò)指定Parent列為1將折扣數(shù)據(jù)設(shè)置成<Store>元素的子元素。

            注意在第三個(gè)SELECT子查詢中我們只包含了那些必需的列,并用NULL補(bǔ)足空列。這個(gè)子查詢包含store_name列,雖然Discount元素并不要用到這個(gè)列,但如果把這個(gè)列也設(shè)置為NULL,則結(jié)果Universal表將不會(huì)按照解析器所要求的那樣以節(jié)點(diǎn)升序排序(不妨自己試一下看看)。Universal表的排序列也可以用Tag列替代。

            為維持結(jié)果Universal表的完整性,第一、二兩個(gè)SELECT語(yǔ)句也用NULL補(bǔ)足以反映為折扣數(shù)據(jù)增加的列。

            為指定新折扣列的元數(shù)據(jù)修改了第一個(gè)SELECT語(yǔ)句。

            通過(guò)在第四個(gè)參數(shù)中聲明element指定Amount列為Discount的一個(gè)元素(element是可在第四個(gè)參數(shù)中聲明的多個(gè)指令之一)。

            下面這個(gè)XML文檔只能用EXPLICIT模式生成:

            結(jié)果XML文檔中不會(huì)顯示出NULL數(shù)據(jù),如折扣lowqty和highqty。

            看來(lái)上面的介紹,大家可能已經(jīng)對(duì)FOR XML的語(yǔ)法有所了解。通過(guò)FOR XML 我們?cè)谀軌蛟赒uery Analyzer 中直接返回一個(gè)XML格式的數(shù)據(jù)或者通過(guò)其他多樣化表現(xiàn)方式將XML格式的數(shù)據(jù)顯示出來(lái),比如可以將數(shù)據(jù)顯示在瀏覽器上。下面這個(gè)例子就使用FOR XML和ADO將數(shù)據(jù)輸出到瀏覽器的例子。

          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的查詢。具體的語(yǔ)法在以后的章節(jié)中將詳細(xì)介紹。
          sQuery = "<ROOT xmlns:sql='urn:schemas-microsoft-com:xml-sql'><sql:query>SELECT * FROM PRODUCTS ORDER BY PRODUCTNAME FOR XML AUTO</sql:query></ROOT>"

          ‘建立ADODB Stream 對(duì)象,ADODB Stream 對(duì)象需要ADO2.5以上版本支持,它可以將記錄集轉(zhuǎn)換為數(shù)據(jù)流。
          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>"

          ‘通過(guò)IE的XML解析器,使用DOM方法將XML的文本轉(zhuǎn)換為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>

           EXPLICIT模式

            EXPLICIT模式比較復(fù)雜,我們將用另外一種方法來(lái)表達(dá)圖1所顯示的查詢。這種方法使得我們能夠完全地控制查詢所生成的XML文檔。首先我們將介紹如何改用EXPLICIT模式編寫圖1所顯示的查詢,然后看看這種方法如何賦予我們遠(yuǎn)遠(yuǎn)超過(guò)AUTO模式的能力。

            下面是圖1查詢用EXPLICIT模式表達(dá)的代碼:

          【圖2 】

          --商店數(shù)據(jù)
          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
          -- 銷售數(shù)據(jù)
          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

            這個(gè)查詢初看起來(lái)有點(diǎn)復(fù)雜,其實(shí)它只是把不同的數(shù)據(jù)集(即這里的Store和Sale)分解到了獨(dú)立的SELECT語(yǔ)句里,然后再用UNION ALL操作符連結(jié)成一個(gè)查詢。

            我們之所以要把查詢寫成上面的形式,是為了讓查詢結(jié)果不僅包含XML文檔所描述的數(shù)據(jù),而且還包含描述XML文檔結(jié)構(gòu)的元數(shù)據(jù)。上述查詢所生成的表稱為Universal表,sqlxml.dll生成XML文檔時(shí)需要這種格式。Universal表對(duì)于編寫代碼的人來(lái)說(shuō)是透明的,但了解這個(gè)表還是很有意義的,它將有助于代碼的開(kāi)發(fā)和調(diào)試。下面是Universal表的一個(gè)例子:

          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模式查詢的元數(shù)據(jù)部分都以紅色表示,黑色表示數(shù)據(jù)。比較查詢和表就可以找出sqlxml.dll生成XML文檔所需要的元素。我們來(lái)仔細(xì)地分析一下它們描述的是什么。

            Tag和Parent列是XML文檔層次結(jié)構(gòu)方面的信息,我們可以認(rèn)為圖2中的每個(gè)SELECT語(yǔ)句代表了一個(gè)XML節(jié)點(diǎn),而Tag和Parent列讓我們指定節(jié)點(diǎn)在文檔層次結(jié)構(gòu)中的位置。如果在第二個(gè)SELECT語(yǔ)句中指定Tag為2、指定Parent為1,就表示為這些數(shù)據(jù)加上了一個(gè)值為2的標(biāo)簽,而這些數(shù)據(jù)的父親是那些標(biāo)簽為1的數(shù)據(jù)(即第一個(gè)SELECT語(yǔ)句)。這就使得我們能夠構(gòu)造出<Store>和<Sale>之間的父-子關(guān)系,而且正如你可能猜想到的,它使得我們可以生成任意合法的XML文檔結(jié)構(gòu)。注意第一個(gè)SELECT命令的parent列設(shè)置成了NULL,這表示<Store>元素處于最頂層的位置。

            以黑色表示的數(shù)據(jù)將成為節(jié)點(diǎn)的屬性或元素,例如,Store_ID就通過(guò)列名提供了這方面的信息。列名字中的“!”是分隔符,總共可分成四項(xiàng)(四個(gè)參數(shù)),其中第四個(gè)參數(shù)是可選的。這些參數(shù)描述的是:

            第一個(gè)參數(shù)描述該列所屬元素的名字,在這里是<Store>元素。

            第二個(gè)是標(biāo)簽編號(hào),它指定了該列信息在XML樹(shù)形結(jié)構(gòu)中所處位置。

            第三個(gè)參數(shù)指定XML文檔內(nèi)的屬性或元素名字。在這里名字指定為id。

            數(shù)據(jù)列默認(rèn)被創(chuàng)建為參數(shù)2所指定節(jié)點(diǎn)的屬性,即id將成為<Store>節(jié)點(diǎn)的屬性。如果要指定id是<Store>的一個(gè)子元素,我們可以使用第四個(gè)可選的參數(shù),這個(gè)參數(shù)的一個(gè)作用就是讓我們把該項(xiàng)指定為元素,例如store!1!id!element。

            由于使用了UNION ALL操作符來(lái)連結(jié)SELECT語(yǔ)句,為了保證SQL查詢的合法性,所有SELECT語(yǔ)句的選擇結(jié)果必須具有相同數(shù)量的列。我們使用NULL關(guān)鍵詞來(lái)補(bǔ)足SELECT語(yǔ)句,從而避免了重復(fù)數(shù)據(jù)。

            通過(guò)EXPLICIT模式查詢所生成的XML文檔和通過(guò)AUTO模式生成的完全相同,那么為什么要?jiǎng)?chuàng)建EXPLICIT模式查詢呢?

            假設(shè)現(xiàn)在有人要求在XML文檔中包含商店的打折信息。查看Pubs數(shù)據(jù)庫(kù),我們得知每個(gè)商店都可以有0到n范圍內(nèi)的折扣率。因此,一種合理的方法是在<Store>元素下面加上子元素<Discount>,這樣我們就得到如下XML文檔結(jié)構(gòu):

          <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>

            這里的改動(dòng)包括:

            要在<Sale>元素所在的層次增加一個(gè)XML元素<Discount>,即<Discount>是<Stroe>的子元素。

            Amount嵌套在<Discount>里面,但不應(yīng)該是<Discount>元素的屬性。

            在AUTO模式中是不可能實(shí)現(xiàn)這些改動(dòng)的。

            下面是創(chuàng)建這個(gè)新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

            為了創(chuàng)建圖2A所顯示的EXPLICIT模式查詢,我們對(duì)圖2的查詢進(jìn)行了如下修改:

            增加了第三個(gè)子查詢提取折扣數(shù)據(jù),通過(guò)Tag列聲明這些數(shù)據(jù)的標(biāo)簽值為3。

            通過(guò)指定Parent列為1將折扣數(shù)據(jù)設(shè)置成<Store>元素的子元素。

            注意在第三個(gè)SELECT子查詢中我們只包含了那些必需的列,并用NULL補(bǔ)足空列。這個(gè)子查詢包含store_name列,雖然Discount元素并不要用到這個(gè)列,但如果把這個(gè)列也設(shè)置為NULL,則結(jié)果Universal表將不會(huì)按照解析器所要求的那樣以節(jié)點(diǎn)升序排序(不妨自己試一下看看)。Universal表的排序列也可以用Tag列替代。

            為維持結(jié)果Universal表的完整性,第一、二兩個(gè)SELECT語(yǔ)句也用NULL補(bǔ)足以反映為折扣數(shù)據(jù)增加的列。

            為指定新折扣列的元數(shù)據(jù)修改了第一個(gè)SELECT語(yǔ)句。

            通過(guò)在第四個(gè)參數(shù)中聲明element指定Amount列為Discount的一個(gè)元素(element是可在第四個(gè)參數(shù)中聲明的多個(gè)指令之一)。

            下面這個(gè)XML文檔只能用EXPLICIT模式生成:

            結(jié)果XML文檔中不會(huì)顯示出NULL數(shù)據(jù),如折扣lowqty和highqty。

            看來(lái)上面的介紹,大家可能已經(jīng)對(duì)FOR XML的語(yǔ)法有所了解。通過(guò)FOR XML 我們?cè)谀軌蛟赒uery Analyzer 中直接返回一個(gè)XML格式的數(shù)據(jù)或者通過(guò)其他多樣化表現(xiàn)方式將XML格式的數(shù)據(jù)顯示出來(lái),比如可以將數(shù)據(jù)顯示在瀏覽器上。下面這個(gè)例子就使用FOR XML和ADO將數(shù)據(jù)輸出到瀏覽器的例子。

          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的查詢。具體的語(yǔ)法在以后的章節(jié)中將詳細(xì)介紹。
          sQuery = "<ROOT xmlns:sql='urn:schemas-microsoft-com:xml-sql'><sql:query>SELECT * FROM PRODUCTS ORDER BY PRODUCTNAME FOR XML AUTO</sql:query></ROOT>"

          ‘建立ADODB Stream 對(duì)象,ADODB Stream 對(duì)象需要ADO2.5以上版本支持,它可以將記錄集轉(zhuǎn)換為數(shù)據(jù)流。
          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>"

          ‘通過(guò)IE的XML解析器,使用DOM方法將XML的文本轉(zhuǎn)換為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>

           EXPLICIT模式

            EXPLICIT模式比較復(fù)雜,我們將用另外一種方法來(lái)表達(dá)圖1所顯示的查詢。這種方法使得我們能夠完全地控制查詢所生成的XML文檔。首先我們將介紹如何改用EXPLICIT模式編寫圖1所顯示的查詢,然后看看這種方法如何賦予我們遠(yuǎn)遠(yuǎn)超過(guò)AUTO模式的能力。

            下面是圖1查詢用EXPLICIT模式表達(dá)的代碼:

          【圖2 】

          --商店數(shù)據(jù)
          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
          -- 銷售數(shù)據(jù)
          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

            這個(gè)查詢初看起來(lái)有點(diǎn)復(fù)雜,其實(shí)它只是把不同的數(shù)據(jù)集(即這里的Store和Sale)分解到了獨(dú)立的SELECT語(yǔ)句里,然后再用UNION ALL操作符連結(jié)成一個(gè)查詢。

            我們之所以要把查詢寫成上面的形式,是為了讓查詢結(jié)果不僅包含XML文檔所描述的數(shù)據(jù),而且還包含描述XML文檔結(jié)構(gòu)的元數(shù)據(jù)。上述查詢所生成的表稱為Universal表,sqlxml.dll生成XML文檔時(shí)需要這種格式。Universal表對(duì)于編寫代碼的人來(lái)說(shuō)是透明的,但了解這個(gè)表還是很有意義的,它將有助于代碼的開(kāi)發(fā)和調(diào)試。下面是Universal表的一個(gè)例子:

          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模式查詢的元數(shù)據(jù)部分都以紅色表示,黑色表示數(shù)據(jù)。比較查詢和表就可以找出sqlxml.dll生成XML文檔所需要的元素。我們來(lái)仔細(xì)地分析一下它們描述的是什么。

            Tag和Parent列是XML文檔層次結(jié)構(gòu)方面的信息,我們可以認(rèn)為圖2中的每個(gè)SELECT語(yǔ)句代表了一個(gè)XML節(jié)點(diǎn),而Tag和Parent列讓我們指定節(jié)點(diǎn)在文檔層次結(jié)構(gòu)中的位置。如果在第二個(gè)SELECT語(yǔ)句中指定Tag為2、指定Parent為1,就表示為這些數(shù)據(jù)加上了一個(gè)值為2的標(biāo)簽,而這些數(shù)據(jù)的父親是那些標(biāo)簽為1的數(shù)據(jù)(即第一個(gè)SELECT語(yǔ)句)。這就使得我們能夠構(gòu)造出<Store>和<Sale>之間的父-子關(guān)系,而且正如你可能猜想到的,它使得我們可以生成任意合法的XML文檔結(jié)構(gòu)。注意第一個(gè)SELECT命令的parent列設(shè)置成了NULL,這表示<Store>元素處于最頂層的位置。

            以黑色表示的數(shù)據(jù)將成為節(jié)點(diǎn)的屬性或元素,例如,Store_ID就通過(guò)列名提供了這方面的信息。列名字中的“!”是分隔符,總共可分成四項(xiàng)(四個(gè)參數(shù)),其中第四個(gè)參數(shù)是可選的。這些參數(shù)描述的是:

            第一個(gè)參數(shù)描述該列所屬元素的名字,在這里是<Store>元素。

            第二個(gè)是標(biāo)簽編號(hào),它指定了該列信息在XML樹(shù)形結(jié)構(gòu)中所處位置。

            第三個(gè)參數(shù)指定XML文檔內(nèi)的屬性或元素名字。在這里名字指定為id。

            數(shù)據(jù)列默認(rèn)被創(chuàng)建為參數(shù)2所指定節(jié)點(diǎn)的屬性,即id將成為<Store>節(jié)點(diǎn)的屬性。如果要指定id是<Store>的一個(gè)子元素,我們可以使用第四個(gè)可選的參數(shù),這個(gè)參數(shù)的一個(gè)作用就是讓我們把該項(xiàng)指定為元素,例如store!1!id!element。

            由于使用了UNION ALL操作符來(lái)連結(jié)SELECT語(yǔ)句,為了保證SQL查詢的合法性,所有SELECT語(yǔ)句的選擇結(jié)果必須具有相同數(shù)量的列。我們使用NULL關(guān)鍵詞來(lái)補(bǔ)足SELECT語(yǔ)句,從而避免了重復(fù)數(shù)據(jù)。

            通過(guò)EXPLICIT模式查詢所生成的XML文檔和通過(guò)AUTO模式生成的完全相同,那么為什么要?jiǎng)?chuàng)建EXPLICIT模式查詢呢?

            假設(shè)現(xiàn)在有人要求在XML文檔中包含商店的打折信息。查看Pubs數(shù)據(jù)庫(kù),我們得知每個(gè)商店都可以有0到n范圍內(nèi)的折扣率。因此,一種合理的方法是在<Store>元素下面加上子元素<Discount>,這樣我們就得到如下XML文檔結(jié)構(gòu):

          <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>

            這里的改動(dòng)包括:

            要在<Sale>元素所在的層次增加一個(gè)XML元素<Discount>,即<Discount>是<Stroe>的子元素。

            Amount嵌套在<Discount>里面,但不應(yīng)該是<Discount>元素的屬性。

            在AUTO模式中是不可能實(shí)現(xiàn)這些改動(dòng)的。

            下面是創(chuàng)建這個(gè)新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

            為了創(chuàng)建圖2A所顯示的EXPLICIT模式查詢,我們對(duì)圖2的查詢進(jìn)行了如下修改:

            增加了第三個(gè)子查詢提取折扣數(shù)據(jù),通過(guò)Tag列聲明這些數(shù)據(jù)的標(biāo)簽值為3。

            通過(guò)指定Parent列為1將折扣數(shù)據(jù)設(shè)置成<Store>元素的子元素。

            注意在第三個(gè)SELECT子查詢中我們只包含了那些必需的列,并用NULL補(bǔ)足空列。這個(gè)子查詢包含store_name列,雖然Discount元素并不要用到這個(gè)列,但如果把這個(gè)列也設(shè)置為NULL,則結(jié)果Universal表將不會(huì)按照解析器所要求的那樣以節(jié)點(diǎn)升序排序(不妨自己試一下看看)。Universal表的排序列也可以用Tag列替代。

            為維持結(jié)果Universal表的完整性,第一、二兩個(gè)SELECT語(yǔ)句也用NULL補(bǔ)足以反映為折扣數(shù)據(jù)增加的列。

            為指定新折扣列的元數(shù)據(jù)修改了第一個(gè)SELECT語(yǔ)句。

            通過(guò)在第四個(gè)參數(shù)中聲明element指定Amount列為Discount的一個(gè)元素(element是可在第四個(gè)參數(shù)中聲明的多個(gè)指令之一)。

            下面這個(gè)XML文檔只能用EXPLICIT模式生成:

            結(jié)果XML文檔中不會(huì)顯示出NULL數(shù)據(jù),如折扣lowqty和highqty。

            看來(lái)上面的介紹,大家可能已經(jīng)對(duì)FOR XML的語(yǔ)法有所了解。通過(guò)FOR XML 我們?cè)谀軌蛟赒uery Analyzer 中直接返回一個(gè)XML格式的數(shù)據(jù)或者通過(guò)其他多樣化表現(xiàn)方式將XML格式的數(shù)據(jù)顯示出來(lái),比如可以將數(shù)據(jù)顯示在瀏覽器上。下面這個(gè)例子就使用FOR XML和ADO將數(shù)據(jù)輸出到瀏覽器的例子。

          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的查詢。具體的語(yǔ)法在以后的章節(jié)中將詳細(xì)介紹。
          sQuery = "<ROOT xmlns:sql='urn:schemas-microsoft-com:xml-sql'><sql:query>SELECT * FROM PRODUCTS ORDER BY PRODUCTNAME FOR XML AUTO</sql:query></ROOT>"

          ‘建立ADODB Stream 對(duì)象,ADODB Stream 對(duì)象需要ADO2.5以上版本支持,它可以將記錄集轉(zhuǎn)換為數(shù)據(jù)流。
          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>"

          ‘通過(guò)IE的XML解析器,使用DOM方法將XML的文本轉(zhuǎn)換為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>


           EXPLICIT模式

            EXPLICIT模式比較復(fù)雜,我們將用另外一種方法來(lái)表達(dá)圖1所顯示的查詢。這種方法使得我們能夠完全地控制查詢所生成的XML文檔。首先我們將介紹如何改用EXPLICIT模式編寫圖1所顯示的查詢,然后看看這種方法如何賦予我們遠(yuǎn)遠(yuǎn)超過(guò)AUTO模式的能力。

            下面是圖1查詢用EXPLICIT模式表達(dá)的代碼:

          【圖2 】

          --商店數(shù)據(jù)
          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
          -- 銷售數(shù)據(jù)
          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

            這個(gè)查詢初看起來(lái)有點(diǎn)復(fù)雜,其實(shí)它只是把不同的數(shù)據(jù)集(即這里的Store和Sale)分解到了獨(dú)立的SELECT語(yǔ)句里,然后再用UNION ALL操作符連結(jié)成一個(gè)查詢。

            我們之所以要把查詢寫成上面的形式,是為了讓查詢結(jié)果不僅包含XML文檔所描述的數(shù)據(jù),而且還包含描述XML文檔結(jié)構(gòu)的元數(shù)據(jù)。上述查詢所生成的表稱為Universal表,sqlxml.dll生成XML文檔時(shí)需要這種格式。Universal表對(duì)于編寫代碼的人來(lái)說(shuō)是透明的,但了解這個(gè)表還是很有意義的,它將有助于代碼的開(kāi)發(fā)和調(diào)試。下面是Universal表的一個(gè)例子:

          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模式查詢的元數(shù)據(jù)部分都以紅色表示,黑色表示數(shù)據(jù)。比較查詢和表就可以找出sqlxml.dll生成XML文檔所需要的元素。我們來(lái)仔細(xì)地分析一下它們描述的是什么。

            Tag和Parent列是XML文檔層次結(jié)構(gòu)方面的信息,我們可以認(rèn)為圖2中的每個(gè)SELECT語(yǔ)句代表了一個(gè)XML節(jié)點(diǎn),而Tag和Parent列讓我們指定節(jié)點(diǎn)在文檔層次結(jié)構(gòu)中的位置。如果在第二個(gè)SELECT語(yǔ)句中指定Tag為2、指定Parent為1,就表示為這些數(shù)據(jù)加上了一個(gè)值為2的標(biāo)簽,而這些數(shù)據(jù)的父親是那些標(biāo)簽為1的數(shù)據(jù)(即第一個(gè)SELECT語(yǔ)句)。這就使得我們能夠構(gòu)造出<Store>和<Sale>之間的父-子關(guān)系,而且正如你可能猜想到的,它使得我們可以生成任意合法的XML文檔結(jié)構(gòu)。注意第一個(gè)SELECT命令的parent列設(shè)置成了NULL,這表示<Store>元素處于最頂層的位置。

            以黑色表示的數(shù)據(jù)將成為節(jié)點(diǎn)的屬性或元素,例如,Store_ID就通過(guò)列名提供了這方面的信息。列名字中的“!”是分隔符,總共可分成四項(xiàng)(四個(gè)參數(shù)),其中第四個(gè)參數(shù)是可選的。這些參數(shù)描述的是:

            第一個(gè)參數(shù)描述該列所屬元素的名字,在這里是<Store>元素。

            第二個(gè)是標(biāo)簽編號(hào),它指定了該列信息在XML樹(shù)形結(jié)構(gòu)中所處位置。

            第三個(gè)參數(shù)指定XML文檔內(nèi)的屬性或元素名字。在這里名字指定為id。

            數(shù)據(jù)列默認(rèn)被創(chuàng)建為參數(shù)2所指定節(jié)點(diǎn)的屬性,即id將成為<Store>節(jié)點(diǎn)的屬性。如果要指定id是<Store>的一個(gè)子元素,我們可以使用第四個(gè)可選的參數(shù),這個(gè)參數(shù)的一個(gè)作用就是讓我們把該項(xiàng)指定為元素,例如store!1!id!element。

            由于使用了UNION ALL操作符來(lái)連結(jié)SELECT語(yǔ)句,為了保證SQL查詢的合法性,所有SELECT語(yǔ)句的選擇結(jié)果必須具有相同數(shù)量的列。我們使用NULL關(guān)鍵詞來(lái)補(bǔ)足SELECT語(yǔ)句,從而避免了重復(fù)數(shù)據(jù)。

            通過(guò)EXPLICIT模式查詢所生成的XML文檔和通過(guò)AUTO模式生成的完全相同,那么為什么要?jiǎng)?chuàng)建EXPLICIT模式查詢呢?

            假設(shè)現(xiàn)在有人要求在XML文檔中包含商店的打折信息。查看Pubs數(shù)據(jù)庫(kù),我們得知每個(gè)商店都可以有0到n范圍內(nèi)的折扣率。因此,一種合理的方法是在<Store>元素下面加上子元素<Discount>,這樣我們就得到如下XML文檔結(jié)構(gòu):

          <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>

            這里的改動(dòng)包括:

            要在<Sale>元素所在的層次增加一個(gè)XML元素<Discount>,即<Discount>是<Stroe>的子元素。

            Amount嵌套在<Discount>里面,但不應(yīng)該是<Discount>元素的屬性。

            在AUTO模式中是不可能實(shí)現(xiàn)這些改動(dòng)的。

            下面是創(chuàng)建這個(gè)新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

            為了創(chuàng)建圖2A所顯示的EXPLICIT模式查詢,我們對(duì)圖2的查詢進(jìn)行了如下修改:

            增加了第三個(gè)子查詢提取折扣數(shù)據(jù),通過(guò)Tag列聲明這些數(shù)據(jù)的標(biāo)簽值為3。

            通過(guò)指定Parent列為1將折扣數(shù)據(jù)設(shè)置成<Store>元素的子元素。

            注意在第三個(gè)SELECT子查詢中我們只包含了那些必需的列,并用NULL補(bǔ)足空列。這個(gè)子查詢包含store_name列,雖然Discount元素并不要用到這個(gè)列,但如果把這個(gè)列也設(shè)置為NULL,則結(jié)果Universal表將不會(huì)按照解析器所要求的那樣以節(jié)點(diǎn)升序排序(不妨自己試一下看看)。Universal表的排序列也可以用Tag列替代。

            為維持結(jié)果Universal表的完整性,第一、二兩個(gè)SELECT語(yǔ)句也用NULL補(bǔ)足以反映為折扣數(shù)據(jù)增加的列。

            為指定新折扣列的元數(shù)據(jù)修改了第一個(gè)SELECT語(yǔ)句。

            通過(guò)在第四個(gè)參數(shù)中聲明element指定Amount列為Discount的一個(gè)元素(element是可在第四個(gè)參數(shù)中聲明的多個(gè)指令之一)。

            下面這個(gè)XML文檔只能用EXPLICIT模式生成:

            結(jié)果XML文檔中不會(huì)顯示出NULL數(shù)據(jù),如折扣lowqty和highqty。

            看來(lái)上面的介紹,大家可能已經(jīng)對(duì)FOR XML的語(yǔ)法有所了解。通過(guò)FOR XML 我們?cè)谀軌蛟赒uery Analyzer 中直接返回一個(gè)XML格式的數(shù)據(jù)或者通過(guò)其他多樣化表現(xiàn)方式將XML格式的數(shù)據(jù)顯示出來(lái),比如可以將數(shù)據(jù)顯示在瀏覽器上。下面這個(gè)例子就使用FOR XML和ADO將數(shù)據(jù)輸出到瀏覽器的例子。

          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的查詢。具體的語(yǔ)法在以后的章節(jié)中將詳細(xì)介紹。
          sQuery = "<ROOT xmlns:sql='urn:schemas-microsoft-com:xml-sql'><sql:query>SELECT * FROM PRODUCTS ORDER BY PRODUCTNAME FOR XML AUTO</sql:query></ROOT>"

          ‘建立ADODB Stream 對(duì)象,ADODB Stream 對(duì)象需要ADO2.5以上版本支持,它可以將記錄集轉(zhuǎn)換為數(shù)據(jù)流。
          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>"

          ‘通過(guò)IE的XML解析器,使用DOM方法將XML的文本轉(zhuǎn)換為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 語(yǔ)言規(guī)范,它是一種基于XML的查詢語(yǔ)言,它能在XML文擋中處理數(shù)據(jù)。SQL Server 2000 中實(shí)現(xiàn)的是該規(guī)范的子集。它把table和views作為XML的組件,并把columns作為XML屬性。SQL Server 2000的XML支持IIS使用URL或者模板的方式提交到SQL Server處理Xpath查詢,并返回XML的結(jié)果。

            支持的功能

            下表顯示 SQL Server 2000 中實(shí)現(xiàn)的 XPath 語(yǔ)言的功能。

          功能 項(xiàng)目
          attributechildparentself
          包括連續(xù)謂詞和嵌套謂詞在內(nèi)的布爾值謂詞  
          所有關(guān)系運(yùn)算符 =, !=, <, <=, >, >=
          算術(shù)運(yùn)算符 +, -, *, div
          顯式轉(zhuǎn)換函數(shù) number()string()Boolean()
          布爾運(yùn)算符 AND, OR
          布爾函數(shù) true()false()not()
          XPath 變量  

            不支持的功能

            下表顯示 SQL Server 2000 中沒(méi)有實(shí)現(xiàn)的 XPath 語(yǔ)言的功能。

          功能 項(xiàng)目
          ancestor、ancestor-or-self、descendant、descendant-or-self (//)、following、following-sibling、namespace、preceding、preceding-sibling
          數(shù)值謂詞  
          算術(shù)運(yùn)算符 mod
          節(jié)點(diǎn)函數(shù) ancestor、ancestor-or-self、descendant、descendant-or-self (//)、following、following-sibling、namespace、preceding、preceding-sibling
          字符串函數(shù) string()、concat()、starts-with()、contains()、substring-before()、substring-after()、substring()、string-length()、normalize()、translate()
          布爾函數(shù) lang()
          數(shù)字函數(shù) sum()、floor()、ceiling()、round()
          Union 運(yùn)算符 |

            XPath 查詢是以表達(dá)式的形式指定的。位置路徑是一種比較常用表達(dá)式,用以選擇相對(duì)于上下文節(jié)點(diǎn)的節(jié)點(diǎn)集。位置路徑表達(dá)式的求值結(jié)果是節(jié)點(diǎn)集。

          XML 文檔
          <root>
            <o(jì)rder productid="Prod-28" unitprice="45.6" quantity="15">
            <discount>0.25</discount>
            </order>
            <o(jì)rder productid="Prod-39" unitprice="18" quantity="21">
            <discount>0.25</discount>
            </order>
            <o(jì)rder productid="Prod-46" unitprice="12" quantity="2">
            <discount>0.25</discount>
            </order>
          </root>

            下面是查詢?cè)揦ML 文檔的XPath位置路徑表達(dá)式,它的含義是返回根節(jié)點(diǎn)下所有<ROOT>子元素下的ProductID屬性的屬性值為 "prod-39"的 <o(jì)rder> 元素。

            位置路徑的類型

            可以分為絕對(duì)位置路徑和相對(duì)位置路徑。

            絕對(duì)位置路徑以文檔的根節(jié)點(diǎn)開(kāi)始,由斜杠 (/) 組成,后面可以是相對(duì)位置路徑。斜杠 (/) 選定文檔的根節(jié)點(diǎn)。

            相對(duì)位置路徑以文檔的上下文節(jié)點(diǎn)(Context)開(kāi)始,由斜杠 (/) 所分開(kāi)的一個(gè)或多個(gè)位置步驟序列組成。每個(gè)步驟都選定相對(duì)于上下文節(jié)點(diǎn)的節(jié)點(diǎn)集。初始步驟序列選定相對(duì)于上下文節(jié)點(diǎn)的節(jié)點(diǎn)集。節(jié)點(diǎn)集中的每個(gè)節(jié)點(diǎn)都用作后續(xù)步驟的上下文節(jié)點(diǎn)。由后續(xù)步驟標(biāo)識(shí)的節(jié)點(diǎn)集聯(lián)接在一起。例如,child::Order/child::OrderDetail 選定上下文節(jié)點(diǎn)的<o(jì)rder> 子元素的 <o(jì)rderdetail> 子元素。

            位置步驟 (絕對(duì)或相對(duì))位置路徑由包含下面三部分的位置步驟組成:

            軸

            軸指定位置步驟選定的節(jié)點(diǎn)與上下文節(jié)點(diǎn)之間的樹(shù)關(guān)系。SQL Server 2000 支持 parent、child、attribute 及 self 軸。

            如果在位置路徑中指定 child 軸,查詢選定的所有節(jié)點(diǎn)都將是上下文節(jié)點(diǎn)的子節(jié)點(diǎn)。
          比如說(shuō)要查詢從當(dāng)前的上下文節(jié)點(diǎn)中選定所有 <Order>節(jié)點(diǎn)的子節(jié)點(diǎn),可以使用 child:: Order

            如果指定 parent 軸,選定的節(jié)點(diǎn)將是上下文節(jié)點(diǎn)的父節(jié)點(diǎn)。
          比如說(shuō)要查詢從當(dāng)前的上下文節(jié)點(diǎn)中選定所有 <Order>節(jié)點(diǎn)的父節(jié)點(diǎn),可以使用 parent:: Order

            如果指定 attribute 軸,選定的節(jié)點(diǎn)是上下文節(jié)點(diǎn)的屬性。
          比如說(shuō)要查詢從當(dāng)前的上下文節(jié)點(diǎn)中選定所有 <Order>節(jié)點(diǎn)的屬性,可以使用 attribute:: Order

            節(jié)點(diǎn)測(cè)試

            節(jié)點(diǎn)測(cè)試指定位置步驟選定的節(jié)點(diǎn)類型。每個(gè)軸(child、parent、attribute 和 self)都具有主要節(jié)點(diǎn)類型。對(duì)于 attribute 軸,主要節(jié)點(diǎn)類型是 <attribute>。對(duì)于 parent、child 和 self 軸,主要節(jié)點(diǎn)類型是 <element>。

            例如,如果位置路徑指定 child::Order,則將選定上下文節(jié)點(diǎn)的 <Order> 子元素。因?yàn)?child 軸以 <element> 為其主要節(jié)點(diǎn)類型,而且如果Order是 <element> 節(jié)點(diǎn),則節(jié)點(diǎn)測(cè)試Order為 TRUE。

            選擇謂詞(零個(gè)或多個(gè))

            謂詞圍繞著軸篩選節(jié)點(diǎn)集。在 XPath 表達(dá)式中指定選擇謂詞與在 SELECT 語(yǔ)句中指定 WHERE 子句相似。謂詞在括號(hào)中指定。應(yīng)用在選擇謂詞中指定的測(cè)試將對(duì)節(jié)點(diǎn)測(cè)試返回的節(jié)點(diǎn)進(jìn)行篩選。對(duì)于要篩選的節(jié)點(diǎn)集中的每個(gè)節(jié)點(diǎn),在對(duì)謂詞表達(dá)式取值時(shí)將此節(jié)點(diǎn)作為上下文節(jié)點(diǎn),將節(jié)點(diǎn)集中的節(jié)點(diǎn)數(shù)作為上下文大小。如果謂詞表達(dá)式對(duì)此節(jié)點(diǎn)取值為 TRUE,則此節(jié)點(diǎn)將包括在最后所得到的節(jié)點(diǎn)集中。

            例如:
            1. Child::Order [attribute::ProductID="Prod-39"] 表示從當(dāng)前的上下文節(jié)點(diǎn)中選定ProductID屬性值為Prod-39的所有 <o(jì)rder>子節(jié)點(diǎn)。

            2. Child::Order [child:: Discount] 表示從當(dāng)前的上下文節(jié)點(diǎn)中選定包含一個(gè)或多個(gè) <Discount> 子節(jié)點(diǎn)的所有 <Order> 子節(jié)點(diǎn)。

            3. Child::Order [not(child:: Discount)] 表示從當(dāng)前的上下文節(jié)點(diǎn)中選定不包含 <Discount> 子節(jié)點(diǎn)的所有 <Order> 子節(jié)點(diǎn)。

            位置步驟的語(yǔ)法

            是用兩個(gè)冒號(hào) (::) 分開(kāi)的軸名和節(jié)點(diǎn)測(cè)試,后面是分別放在方括號(hào)中的零個(gè)或多個(gè)表達(dá)式。

            例如,在 XPath 表達(dá)式(位置路徑)child::Order[attribute::ProductID="prod-39"]中,選定上下文節(jié)點(diǎn)的所有 <o(jì)rder> 子元素。然后將謂詞中的測(cè)試應(yīng)用于節(jié)點(diǎn)集,將只返回 ProductID屬性的屬性值為 "prod-39"的 <o(jì)rder> 元素節(jié)點(diǎn)。

            縮略語(yǔ)法

            Sqlservr2000支持下面的位置路徑縮略語(yǔ)法:
            attribute::可以縮略為 @。
            比如:[attribute::ProductID="Prod-39"] 可以縮寫成 [@ProductID =" Prod-39"]

            child::可以在位置步驟中省略。
            比如:位置路徑child::ROOT/child::Orde可以縮寫成 ROOT /Order

            self::node() 可縮略為一個(gè)句點(diǎn) (.),而 parent::node() 可縮略兩個(gè)句點(diǎn) (..)。

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

          posted on 2005-02-28 21:34 閱讀(185) 評(píng)論(0)  編輯  收藏 所屬分類: 數(shù)據(jù)庫(kù)相關(guān)

          主站蜘蛛池模板: 酉阳| 卢氏县| 成安县| 贡嘎县| 阜南县| 育儿| 乐都县| 榆社县| 景德镇市| 北海市| 舟山市| 平阴县| 喀什市| 精河县| 弥渡县| 绥江县| 古丈县| 新建县| 金溪县| 庄河市| 深水埗区| 赤峰市| 栖霞市| 聂荣县| 伊春市| 集贤县| 新蔡县| 宣城市| 竹山县| 汶上县| 行唐县| 拉孜县| 东宁县| 临沂市| 如皋市| 林州市| 称多县| 乌恰县| 鄢陵县| 疏勒县| 大港区|