作者簡介:]Wayne,新一代程序員,十二歲時開始學習編程,十三歲時擁有自己的電腦,先後學過Basic、Pascal、C、FOXPRO、VB、Delphi、C++、SQL,學習Java語言後,遂成為Java的瘋狂崇拜者,現就讀於中國科技大學。
引言
我們可以很簡單的使用ADO訪問數據庫中的數據,但是,如果我們想把從數據庫中檢索得到的數據以XML的格式顯示出來的話,就要費點神了,當然,我們可以去找一些現成的應用程序或者是把現有的存儲過程修改一下,來完成這個想法。
雖說ADO2.5宣稱支持XML,但是它仍需要一個額外的層來處理把數據轉化成XML的過程。幸好有了SQL Server 2000,它宣稱可以直接從數據庫中取出數據,而不通過ADO2.5直接把數據以XML方式顯示出來。這個功能極大的提高了構造分布式、數據集中的應用程序的性能,因為這個特性消除了不必要的代碼層。
讓我們看一看,為了支持XML,SQL Server 2000添加了什麼新的特性:
1、能夠使用 HTTP 訪問 SQL Server。
2、支持 XDR(XML數據簡化)架構並且能夠指定對這些架構的 XPath 查詢。
3、能夠檢索並寫入 XML 數據:
使用 SELECT 語句和 FOR XML 子句檢索 XML 數據。
使用 OPENXML 行集提供程序寫入 XML 數據。
使用 XPath 查詢語言檢索 XML 數據。
4、增強了 Microsoft SQL Server 2000 OLE DB 提供程序 (SQLOLEDB),使得可以將 XML 文檔設置為命令文本並以流的形式返回結果集。
可見,我們可以使用好幾種方法使用SQL Server 2000來訪問XML格式的數據:第一種,在 URL 中執行的查詢可以直接訪問 SQL Server 2000生成XML文檔(也可以調用存儲在Web服務器上的XML模版生成XML數據文件)。第二種,可以使用SELECT命令和FOR XML關鍵字,通過調用一個存儲過程或是通過使用XPath查詢來取得XML數據。SQL Server 2000 完全支持 XDR(XML數據簡化)架構,具有映射XML元素和屬性到表和字段中的功能。下面,我就探討一下SQL Server 2000對XML的支持特性。
一、配置SQL Server 2000的IIS虛擬目錄
在本文的開始,我想先談一談如何配置SQL Server 2000的IIS虛擬目錄。SQL Server 2000 允許為IIS創建一個虛擬目錄,用來直接訪問一個SQL數據庫中的數據。一旦在一台配置了IIS的計算機上安裝了SQL Server 2000,就可以運行SQL Server 的 IIS 虛擬目錄管理實用工具來配置SQL Server 2000的IIS虛擬目錄。
好,讓我們開始配置過程吧!
在"SQL Server 工具"程序組中單擊"在 IIS 中配置 SQL XML 支持",這時就會出現一個與IIS管理器相似的界面。展開服務器,選取默認的 Web 站點,點右鍵,在彈出的菜單中選取“新建”選項,然後單擊"虛擬目錄"命令。新虛擬目錄的屬性頁將顯示在屏幕上。在"新的虛擬目錄屬性"對話框的"常規"選項卡上,輸入虛擬目錄的名稱,在本例中,請輸入Northwind和物理目錄路徑(例如 C:\Inetpub\Wwwroot\Northwind,假設在 C:\Inetpub\Wwwroot 目錄中已創建了 Northwind子目錄),當然我們也可以使用“浏覽”按鈕選擇目錄。在“安全性”選項卡上,填入有效的 SQL Server 登錄信息,在進入下一個選項卡時,它將要求你確認剛才輸入的密碼。在“數據源”選項卡上,在“SQL Server”框中輸入服務器的名稱,在“數據庫”框中,輸入 Northwind 作為默認數據庫的名稱。
Set ObjXML = CreateObject("SQLVDir.SQLVDirControl")
ObjXML.Connect 'Connect to the local computer and Web site "1"
Set ObjVDirs = ObjXML.SQLVDirs
Set ObjVDir = ObjVDirs.AddVirtualDirectory("Northwind")
ObjVDir.PhysicalPath = "C:\Inetpub\wwwroot\northwind"
ObjVDir.UserName = "wayne" 'SQL Server login
ObjVDir.PassWord = "" 'SQL Server PassWord
ObjVDir.DatabaseName = "Northwind"
objVDir.AllowFlags = 73
Set objVNames = objVDir.VirtualNames
objVNames.AddVirtualName "dbobject", 1, ""
objVNames.AddVirtualName "schema", 2,"C:\Inetpub\wwwroot\northwind\schema"
objVNames.AddVirtualName "template", 4 , "C:\Inetpub\wwwroot\northwind\template"
objXML.Disconnect
msgbox "Done."
<?XML version="1.0" encoding="utf-8" ?>
<root>
<Customers CustomerID="ANTON" CompanyName="Antonio Moreno Taquería" ContactName="Antonio Moreno" ContactTitle="Owner" Address="Mataderos 2312" City="México D.F."
PostalCode="05023" Country="Mexico" Phone="(5) 555-3932" />
</root>
http://localhost/northwind?sql=SELECT
Customer.CustomerID%2cCustomer.Contact
Name%2c%5bOrder%5d.OrderID+FROM+Customers+
Customer+INNER+JOIN+Orders+%5bOrder%
5d+ON+Customer.CustomerID%3d%5bOrder%
5d.CustomerID+FOR+XML+AUTO&root=Northwind
SELECT Customers.CustomerID, Orders.OrderID, Orders.OrderDate
FROM Customers, Orders
WHERE Customers.CustomerID = Orders.CustomerID
ORDER BY Customers.CustomerID
FOR XML RAW
<row CustomerID="ALFKI" OrderID="10643" OrderDate="1997-08-25T00:00:00"/>
<row CustomerID="ANATR" OrderID="10308" OrderDate="1996-09-18T00:00:00"/>
<row CustomerID="ANATR" OrderID="10
625" OrderDate="1997-08-08T
00:00:00"/>
<row CustomerID="AROUT" OrderID="10355" OrderDate="1996-11-15T00:00:00"/>
SELECT C.CustomerID, O.OrderID, O.OrderDate
FROM Customers C LEFT OUTER JOIN Orders O ON C.CustomerID = O.CustomerID ORDER BY C.CustomerID FOR XML RAW
<row CustomerID="BONAP" OrderID="11076" OrderDate="1998-05-06T00:00:00"/>
<row CustomerID="FISSA"/>
<row CustomerID="PARIS"/>
<row CustomerID="RICSU" OrderID="11075" OrderDate="1998-05-06T00:00:00"/>
CREATE PROCEDURE GetXML
(
@CustomerID varchar(5)
)
AS
BEGIN
SELECT CustomerID, CompanyName,ContactName
FROM Customers
WHERE CustomerID LIKE @CustomerID + '%'
FOR XML AUTO
END
file2.XML
<Northwind XMLns:sql=
"urn:schemas-microsoft-com:XML-sql">
<sql:query>
SELECT Customers.CustomerID, Customers.ContactName,
Orders.OrderID, Orders.CustomerID
FROM Customers
INNER JOIN Orders
ON Customers.CustomerID = Orders.CustomerID
FOR XML AUTO
</sql:query>
</Northwind>
這段代碼中使用了一個名為sql的前綴和一個URI urn:schemas-microsoft-com:xml-sql,這個前綴用來標識使用在 SQL Server XML ISAPI上的元素。有一個元素名為query,顧名思義它就是用來標記模板文件中的SQL 查詢語句。好,讓我們來演示一下如何使用這個模板吧!請在地址欄中輸入,http://localhost/northwind/templates/file2.XML,當然你也可以根據你的需要改變相應的服務器名和虛擬目錄名。
讓我們把這個 URL拆分成單獨的片段,進行分析,你可以看見,我們先使用了 northwind虛擬根,然後使用templates虛擬目錄名,如前我們說過,該虛擬目錄名已經映射到templates的物理目錄中。最後, URL給出了模板文件的名稱。執行這個模板,浏覽器就會把表中customers元素下嵌套的不同的訂單以XML文檔的形式顯示出來。
使用模板而不使用 URL查詢有許多優點。首先,現在一個最終用戶就沒有改變SQL語句的權力了,去除“通過URL查詢訪問 SQL Server服務器”的選項 ,就只有SQL Server XML ISAPI可以用來處理模板文件,這就避免未經授權的 插入、更新和刪除程序被執行。其次, XML模板支持動態加入參數,這就允許你不用更改模板文件就可以更改一個 SQL WHERE子句的值。
使用參數,就像插入一個 XML header元素一樣簡單的,在 header元素中,定義了一個 param元素,使用一個值為CustomerID的名稱屬性。這個參數被賦予一個默認值"A",你可以象在一個存儲過程中一樣在模板文件中使用這個參數,只要在這個參數前添加一個@,然後把它放入SQL語句或用來調用一個存儲過程就可以了。請見下面的代碼。<Northwind xmlns:sql="urn:schemas-microsoft-com:XML-sql">
<sql:header>
<sql:param name='CustomerID'>A</sql:param>
</sql:header>
<sql:query>
SELECT Customers.CustomerID, Customers.ContactName,
Orders.OrderID, Orders.CustomerID
FROM Customers
INNER JOIN Orders
ON Customers.CustomerID = Orders.CustomerID
WHERE Customers.CustomerID LIKE @CustomerID + '%'
FOR XML AUTO
</sql:query>
</Northwind>
在本例中,CustomerID參數被一個WHERE子句使用。如果把參數設為"B",SQL 語句就會從Customers和Orders表中返回所有的CustomerID以B開頭的行。調用模板並傳遞正確的CustomerID參數值,只要在查詢字符串之後加上參數名和參數值,如:http://localhost/northwind/templates/file2.xml?CustomerID=B即可,就這麼簡單。
<Northwind XMLns:sql=
"urn:schemas-microsoft-com:
XML-sql">
<sql:xpath-query mapping-schema=
"file4.xdr">
/Customer[@CustomerID=
'ALFKI']/Order
</sql:xpath-query>
</Northwind>
<?XML version="1.0" ?>
<Schema xmlns="urn:schemas-microsoft-com:XML-data"
XMLns:dt="urn:schemas-microsoft-com:datatypes"
xmlns:sql="urn:schemas-microsoft-com:XML-sql">
<ElementType name="Customer" sql:relation="Customers">
<AttributeType name="CustomerID" dt:type="id" />
<AttributeType name="CompanyName" />
<AttributeType name="ContactName" />
<AttributeType name="City" />
<AttributeType name="Fax" />
<AttributeType name="Orders" dt:type=
"idrefs" sql:id-prefix="Ord-" />
<attribute type="CustomerID" />
<attribute type="CompanyName" />
<attribute type="ContactName" />
<attribute type="City" />
<attribute type="Fax" />
<attribute type="Orders" sql:relation=
"Orders" sql:fIEld="OrderID">
<sql:relationship
key-relation="Customers"
key="CustomerID"
foreign-relation="Orders"
foreign-key="CustomerID" />
</attribute>
<element type="Order">
<sql:relationship
key-relation="Customers"
key="CustomerID"
foreign-relation="Orders"
foreign-key="CustomerID" />
</element>
</ElementType>
<ElementType name="Order" sql:relation="Orders">
<AttributeType name="OrderID" dt:type=
"id" sql:id-prefix="Ord-" />
<AttributeType name="EmployeeID" />
<AttributeType name="OrderDate" />
<AttributeType name="RequiredDate" />
<AttributeType name="ShippedDate" />
<attribute type="OrderID"/>
<attribute type="EmployeeID" />
<attribute type="OrderDate" />
<attribute type="RequiredDate" />
<attribute type="ShippedDate" />
<element type="OrderDetail">
<sql:relationship
key-relation="Orders"
key="OrderID"
foreign-relation="[Order Details]"
foreign-key="OrderID" />
</element>
<element type="Employee">
<sql:relationship
key-relation="Orders"
key="EmployeeID"
foreign-relation="Employees"
foreign-key="EmployeeID" />
</element>
</ElementType>
<ElementType name="OrderDetail" sql:relation=
"[Order Details]"
sql:key-fIElds="OrderID ProductID">
<AttributeType name="ProductID" dt:type="idref"
sql:id-prefix="Prod-" />
<AttributeType name="UnitPrice"/>
<AttributeType name="Quantity" />
<attribute type="ProductID" />
<attribute type="UnitPrice"/>
<attribute type="Quantity" />
<element type="Discount" sql:fIEld="Discount"/>
</ElementType>
<ElementType name="Discount" dt:type="string"
sql:relation="[Order Details]"/>
<ElementType name="Employee" sql:relation="Employees">
<AttributeType name="EmployeeID" dt:type="idref"
sql:id-prefix="Emp-" />
<AttributeType name="LastName" />
<AttributeType name="FirstName" />
<AttributeType name="Title" />
<attribute type="EmployeeID"/>
<attribute type="LastName" />
<attribute type="FirstName" />
<attribute type="Title" />
</ElementType>
</Schema>
<Northwind XMLns:sql=
"urn:schemas-microsoft-com:XML-sql">
<sql:xpath-query mapping-schema=
"listing4.xdr">
/Customer[@CustomerID=
'ALFKI']/Order/
Employee[@LastName='Suyama']
</sql:xpath-query>
</Northwind>
<Northwind XMLns:sql=
"urn:schemas-microsoft-com:XML-sql">
<Employee EmployeeID="Emp-6"
LastName="Suyama"
FirstName="Michael"
Title="Sales
Representative"/>
</Northwind>
<Northwind xmlns:sql="urn:schemas-microsoft-com:XML-sql">
<sql:header>
<sql:param name="ID"/>
</sql:header>
<sql:xpath-query mapping-schema="listing4.xdr"> {{should this be "listing6.xdr"?}}
/Customer/Order[@OrderID=$ID]
</sql:xpath-query>
</Northwind>
<Northwind xmlns:sql="urn:schemas-microsoft-com:XML-sql">
<Order OrderID="Ord-10643" EmployeeID=
"6" OrderDate="1997-08-25T00:00:00" RequiredDate=
"1997-09-22T00:00:00" ShippedDate=
"1997-09-02T00:00:00">
<Employee EmployeeID="Emp-6" LastName=
"Suyama" FirstName="Michael" Title=
"Sales Representative" />
<OrderDetail ProductID="Prod-28" UnitPrice=
"45.6" Quantity="15">
<Discount>0.25</Discount>
</OrderDetail>
<OrderDetail ProductID="Prod-39" UnitPrice=
"18" Quantity="21">
<Discount>0.25</Discount>
</OrderDetail>
<OrderDetail ProductID="Prod-46" UnitPrice=
"12" Quantity="2">
<Discount>0.25</Discount>
</OrderDetail>
</Order>
</Northwind>
小結
通過使用上面我介紹的幾種技術,我們可以直接從SQL Server 2000數據庫中直接取得XML數據。如我所介紹,URL查詢、XML模板文件、XDR架構和XPath查詢提供了強大的功能,從SQL Server 2000中直接獲得XML數據。除此之外,還有很多重要的概念,由於篇幅有限在本文中不可能詳述,如FOR XML EXPLICIT查詢和OPENXML這些技術,我會在以後的文章中進一步進行討論,請大家等待。