<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 3, 文章 - 152, 評論 - 17, 引用 - 0
    數據加載中……

    SQL Server 2000 XML之七種兵器

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

      兵器之一:FOR XML

      在SQL Server 2000中,標準的T-SQL SELECT語句包括FOR XML子句,它以XML文檔形式返回一個查詢結果。新的FOR XML子句有三種模式——RAW,AUTO,和EXPLICIT,每個都能對XML文檔格式提供附加標準的控制。

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

      為了從SQL Server提取XML格式的數據,T-SQL中加入了一個FOR XML命令。在查詢命令中使用FOR XML命令使得查詢結果以XML格式出現。FOR XML命令有三種模式:RAW,AUTO和EXPLICIT。圖1所顯示的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

      這個查詢初看起來有點復雜,其實它只是把不同的數據集(即這里的Store和Sale)分解到了獨立的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文檔所需要的元素。我們來仔細地分析一下它們描述的是什么。

      Tag和Parent列是XML文檔層次結構方面的信息,我們可以認為圖2中的每個SELECT語句代表了一個XML節點,而Tag和Parent列讓我們指定節點在文檔層次結構中的位置。如果在第二個SELECT語句中指定Tag為2、指定Parent為1,就表示為這些數據加上了一個值為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數據庫,我們得知每個商店都可以有0到n范圍內的折扣率。因此,一種合理的方法是在<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。

      通過指定Parent列為1將折扣數據設置成<Store>元素的子元素。

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

      為維持結果Universal表的完整性,第一、二兩個SELECT語句也用NULL補足以反映為折扣數據增加的列。

      為指定新折扣列的元數據修改了第一個SELECT語句。

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

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

      結果XML文檔中不會顯示出NULL數據,如折扣lowqty和highqty。

      看來上面的介紹,大家可能已經對FOR XML的語法有所了解。通過FOR XML 我們在能夠在Query Analyzer 中直接返回一個XML格式的數據或者通過其他多樣化表現方式將XML格式的數據顯示出來,比如可以將數據顯示在瀏覽器上。下面這個例子就使用FOR XML和ADO將數據輸出到瀏覽器的例子。

    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:query>SELECT * 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>"

    ‘通過IE的XML解析器,使用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>

     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

      這個查詢初看起來有點復雜,其實它只是把不同的數據集(即這里的Store和Sale)分解到了獨立的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文檔所需要的元素。我們來仔細地分析一下它們描述的是什么。

      Tag和Parent列是XML文檔層次結構方面的信息,我們可以認為圖2中的每個SELECT語句代表了一個XML節點,而Tag和Parent列讓我們指定節點在文檔層次結構中的位置。如果在第二個SELECT語句中指定Tag為2、指定Parent為1,就表示為這些數據加上了一個值為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數據庫,我們得知每個商店都可以有0到n范圍內的折扣率。因此,一種合理的方法是在<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。

      通過指定Parent列為1將折扣數據設置成<Store>元素的子元素。

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

      為維持結果Universal表的完整性,第一、二兩個SELECT語句也用NULL補足以反映為折扣數據增加的列。

      為指定新折扣列的元數據修改了第一個SELECT語句。

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

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

      結果XML文檔中不會顯示出NULL數據,如折扣lowqty和highqty。

      看來上面的介紹,大家可能已經對FOR XML的語法有所了解。通過FOR XML 我們在能夠在Query Analyzer 中直接返回一個XML格式的數據或者通過其他多樣化表現方式將XML格式的數據顯示出來,比如可以將數據顯示在瀏覽器上。下面這個例子就使用FOR XML和ADO將數據輸出到瀏覽器的例子。

    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:query>SELECT * 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>"

    ‘通過IE的XML解析器,使用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>

     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

      這個查詢初看起來有點復雜,其實它只是把不同的數據集(即這里的Store和Sale)分解到了獨立的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文檔所需要的元素。我們來仔細地分析一下它們描述的是什么。

      Tag和Parent列是XML文檔層次結構方面的信息,我們可以認為圖2中的每個SELECT語句代表了一個XML節點,而Tag和Parent列讓我們指定節點在文檔層次結構中的位置。如果在第二個SELECT語句中指定Tag為2、指定Parent為1,就表示為這些數據加上了一個值為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數據庫,我們得知每個商店都可以有0到n范圍內的折扣率。因此,一種合理的方法是在<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。

      通過指定Parent列為1將折扣數據設置成<Store>元素的子元素。

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

      為維持結果Universal表的完整性,第一、二兩個SELECT語句也用NULL補足以反映為折扣數據增加的列。

      為指定新折扣列的元數據修改了第一個SELECT語句。

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

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

      結果XML文檔中不會顯示出NULL數據,如折扣lowqty和highqty。

      看來上面的介紹,大家可能已經對FOR XML的語法有所了解。通過FOR XML 我們在能夠在Query Analyzer 中直接返回一個XML格式的數據或者通過其他多樣化表現方式將XML格式的數據顯示出來,比如可以將數據顯示在瀏覽器上。下面這個例子就使用FOR XML和ADO將數據輸出到瀏覽器的例子。

    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:query>SELECT * 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>"

    ‘通過IE的XML解析器,使用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>

     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

      這個查詢初看起來有點復雜,其實它只是把不同的數據集(即這里的Store和Sale)分解到了獨立的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文檔所需要的元素。我們來仔細地分析一下它們描述的是什么。

      Tag和Parent列是XML文檔層次結構方面的信息,我們可以認為圖2中的每個SELECT語句代表了一個XML節點,而Tag和Parent列讓我們指定節點在文檔層次結構中的位置。如果在第二個SELECT語句中指定Tag為2、指定Parent為1,就表示為這些數據加上了一個值為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數據庫,我們得知每個商店都可以有0到n范圍內的折扣率。因此,一種合理的方法是在<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。

      通過指定Parent列為1將折扣數據設置成<Store>元素的子元素。

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

      為維持結果Universal表的完整性,第一、二兩個SELECT語句也用NULL補足以反映為折扣數據增加的列。

      為指定新折扣列的元數據修改了第一個SELECT語句。

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

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

      結果XML文檔中不會顯示出NULL數據,如折扣lowqty和highqty。

      看來上面的介紹,大家可能已經對FOR XML的語法有所了解。通過FOR XML 我們在能夠在Query Analyzer 中直接返回一個XML格式的數據或者通過其他多樣化表現方式將XML格式的數據顯示出來,比如可以將數據顯示在瀏覽器上。下面這個例子就使用FOR XML和ADO將數據輸出到瀏覽器的例子。

    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:query>SELECT * 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>"

    ‘通過IE的XML解析器,使用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>

     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

      這個查詢初看起來有點復雜,其實它只是把不同的數據集(即這里的Store和Sale)分解到了獨立的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文檔所需要的元素。我們來仔細地分析一下它們描述的是什么。

      Tag和Parent列是XML文檔層次結構方面的信息,我們可以認為圖2中的每個SELECT語句代表了一個XML節點,而Tag和Parent列讓我們指定節點在文檔層次結構中的位置。如果在第二個SELECT語句中指定Tag為2、指定Parent為1,就表示為這些數據加上了一個值為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數據庫,我們得知每個商店都可以有0到n范圍內的折扣率。因此,一種合理的方法是在<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。

      通過指定Parent列為1將折扣數據設置成<Store>元素的子元素。

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

      為維持結果Universal表的完整性,第一、二兩個SELECT語句也用NULL補足以反映為折扣數據增加的列。

      為指定新折扣列的元數據修改了第一個SELECT語句。

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

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

      結果XML文檔中不會顯示出NULL數據,如折扣lowqty和highqty。

      看來上面的介紹,大家可能已經對FOR XML的語法有所了解。通過FOR XML 我們在能夠在Query Analyzer 中直接返回一個XML格式的數據或者通過其他多樣化表現方式將XML格式的數據顯示出來,比如可以將數據顯示在瀏覽器上。下面這個例子就使用FOR XML和ADO將數據輸出到瀏覽器的例子。

    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:query>SELECT * 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>"

    ‘通過IE的XML解析器,使用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>


     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

      這個查詢初看起來有點復雜,其實它只是把不同的數據集(即這里的Store和Sale)分解到了獨立的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文檔所需要的元素。我們來仔細地分析一下它們描述的是什么。

      Tag和Parent列是XML文檔層次結構方面的信息,我們可以認為圖2中的每個SELECT語句代表了一個XML節點,而Tag和Parent列讓我們指定節點在文檔層次結構中的位置。如果在第二個SELECT語句中指定Tag為2、指定Parent為1,就表示為這些數據加上了一個值為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數據庫,我們得知每個商店都可以有0到n范圍內的折扣率。因此,一種合理的方法是在<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。

      通過指定Parent列為1將折扣數據設置成<Store>元素的子元素。

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

      為維持結果Universal表的完整性,第一、二兩個SELECT語句也用NULL補足以反映為折扣數據增加的列。

      為指定新折扣列的元數據修改了第一個SELECT語句。

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

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

      結果XML文檔中不會顯示出NULL數據,如折扣lowqty和highqty。

      看來上面的介紹,大家可能已經對FOR XML的語法有所了解。通過FOR XML 我們在能夠在Query Analyzer 中直接返回一個XML格式的數據或者通過其他多樣化表現方式將XML格式的數據顯示出來,比如可以將數據顯示在瀏覽器上。下面這個例子就使用FOR XML和ADO將數據輸出到瀏覽器的例子。

    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:query>SELECT * 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>"

    ‘通過IE的XML解析器,使用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 中實現的是該規范的子集。它把table和views作為XML的組件,并把columns作為XML屬性。SQL Server 2000的XML支持IIS使用URL或者模板的方式提交到SQL Server處理Xpath查詢,并返回XML的結果。

      支持的功能

      下表顯示 SQL Server 2000 中實現的 XPath 語言的功能。

    功能 項目
    attribute、child、parentself
    包括連續謂詞和嵌套謂詞在內的布爾值謂詞  
    所有關系運算符 =, !=, <, <=, >, >=
    算術運算符 +, -, *, div
    顯式轉換函數 number()string()、Boolean()
    布爾運算符 AND, OR
    布爾函數 true()false()not()
    XPath 變量  

      不支持的功能

      下表顯示 SQL Server 2000 中沒有實現的 XPath 語言的功能。

    功能 項目
    ancestor、ancestor-or-self、descendant、descendant-or-self (//)、following、following-sibling、namespace、preceding、preceding-sibling
    數值謂詞  
    算術運算符 mod
    節點函數 ancestor、ancestor-or-self、descendant、descendant-or-self (//)、following、following-sibling、namespace、preceding、preceding-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">
      <discount>0.25</discount>
      </order>
      <order productid="Prod-39" unitprice="18" quantity="21">
      <discount>0.25</discount>
      </order>
      <order productid="Prod-46" unitprice="12" quantity="2">
      <discount>0.25</discount>
      </order>
    </root>

      下面是查詢該XML 文檔的XPath位置路徑表達式,它的含義是返回根節點下所有<ROOT>子元素下的ProductID屬性的屬性值為 "prod-39"的 <order> 元素。

      位置路徑的類型

      可以分為絕對位置路徑和相對位置路徑。

      絕對位置路徑以文檔的根節點開始,由斜杠 (/) 組成,后面可以是相對位置路徑。斜杠 (/) 選定文檔的根節點。

      相對位置路徑以文檔的上下文節點(Context)開始,由斜杠 (/) 所分開的一個或多個位置步驟序列組成。每個步驟都選定相對于上下文節點的節點集。初始步驟序列選定相對于上下文節點的節點集。節點集中的每個節點都用作后續步驟的上下文節點。由后續步驟標識的節點集聯接在一起。例如,child::Order/child::OrderDetail 選定上下文節點的<order> 子元素的 <orderdetail> 子元素。

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

      軸

      軸指定位置步驟選定的節點與上下文節點之間的樹關系。SQL Server 2000 支持 parent、child、attribute 及 self 軸。

      如果在位置路徑中指定 child 軸,查詢選定的所有節點都將是上下文節點的子節點。
    比如說要查詢從當前的上下文節點中選定所有 <Order>節點的子節點,可以使用 child:: Order

      如果指定 parent 軸,選定的節點將是上下文節點的父節點。
    比如說要查詢從當前的上下文節點中選定所有 <Order>節點的父節點,可以使用 parent:: Order

      如果指定 attribute 軸,選定的節點是上下文節點的屬性。
    比如說要查詢從當前的上下文節點中選定所有 <Order>節點的屬性,可以使用 attribute:: Order

      節點測試

      節點測試指定位置步驟選定的節點類型。每個軸(child、parent、attribute 和 self)都具有主要節點類型。對于 attribute 軸,主要節點類型是 <attribute>。對于 parent、child 和 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"]

    posted on 2005-02-28 21:34 閱讀(183) 評論(0)  編輯  收藏 所屬分類: 數據庫相關

    主站蜘蛛池模板: 亚洲阿v天堂在线| 国产亚洲精品AA片在线观看不加载 | 亚洲另类图片另类电影| 午夜老司机永久免费看片| 亚洲AV无码日韩AV无码导航 | 91精品国产免费久久国语蜜臀 | 全黄a免费一级毛片人人爱| 亚洲精品9999久久久久无码| 色婷婷7777免费视频在线观看| 亚洲H在线播放在线观看H| 99久久综合国产精品免费| 亚洲看片无码在线视频| 日韩高清在线免费看| 免费手机在线看片| 伊人久久综在合线亚洲91| 中文字幕无码免费久久| 亚洲最大在线观看| 四虎www成人影院免费观看| 日韩亚洲人成网站| 亚洲国产另类久久久精品小说| 国产日韩AV免费无码一区二区| 亚洲美女视频网站| 四虎成人免费网址在线| 永久免费观看黄网站| 久久久久亚洲AV无码网站| 成人免费无码大片a毛片软件| 深夜a级毛片免费视频| 国产成人亚洲精品青草天美| 114一级毛片免费| 青青免费在线视频| 亚洲毛片在线观看| 日本特黄特色免费大片| 一区二区三区无码视频免费福利| 亚洲精品白色在线发布| 亚洲?V无码乱码国产精品| 99在线观看精品免费99| 久久久久久亚洲精品无码| 在线观看国产区亚洲一区成人| 日本免费一区二区三区| 亚洲AV永久无码精品放毛片 | 亚洲午夜一区二区电影院|