由於xml(可擴展標記語言:eXtensible Markup Language)真正的平台無關性,它正在逐漸成為資料傳輸的主要媒體。 XML是一種自描述的語言,數據本身就已經包含了元數據,即關於數據本身的信 息。例如:「孟子E章1757281793923net_lover1807581793923」這組數據,從字面很難看出它代表什麼意思,也不清楚它有幾個數據段組成,但是,如果用XML來做如下的描述,我們就可以清楚地看到每個資料段所代表的意義:
<PersonData> <Person> <姓名>孟子E章</姓名> <身高>175</身高> <体重>72</体重> <电话>81793923</电话> </Person> <Person> <姓名>net_lover</姓名> <身高>180</身高> <体重>75</体重> <电话>81793923</电话> </Person> </PersonData>
從上面的一段XML中,我們不但可以清楚地看到每一個資料代表的是什麼意思了,而且還可以知道資料的分割位置。在我們平常的應用中,我們得到的結果可能是 陣列、集合或記錄集的表現形式,我們該如何把它們轉換成自描述的XML格式的資料呢?從資料形式來看,XML是簡單的純字串的文字格式,字串在傳遞時是非常簡單、快速且是容易的,數組在透過引用進行傳遞時有時是很慢的,而且處理起來很麻煩,而集合和記錄集都是對象,在處理時會導致計算機性能的下降, 而這些對像都是與特定的平台相關聯的,這就要求平台有內建的處理機制來處理對象的操作。 XML已經是W3C的標準,是平台無關的,我們的電腦的唯一要求就是能夠處理簡單的XML字串,即XML解析器,它能夠解析XML字串,能夠透過一種介面很容易地把資料分解成一個獨立的資料段,以便我們能夠進行存取。 XML解析器都很小,效能也很好,在每種平台上都可以找到。一旦我們接收到XML資料並把它解析成上面的範例的樣式後,我們就可以透過XSLT (eXstensible Stylesheet Language Transformations)把他們轉換成不同的表現形式。利用XML的資料格式進行資料傳輸,將會使我們編寫應用程式程式碼的工作更簡單輕鬆,而且具有 有良好的可擴展性。
下面,我們就來看看如何來轉換我們的資料。我們的例子是在Microsoft Windows 2000,IIS5,MSXML3和ADO2.6下編寫的,範例資料採用Microsoft SQL Server7.0自帶的Northwind範例資料庫。之所以採用SQL Server7而不採用支援XML的SQL Server2000,是考慮到通用性的原則,我們的目的是:處理不同類型的資料來源所得到的記錄集,而不僅僅是像SQL Server2000那樣的支援XML輸出的資料來源。使用ADO,是因為它形式多樣,可以處理不同類型的資料來源;使用XML,因為它能夠快速傳輸和解 析。但本例的處理方法也適合在任何具有Micrsoft XML解析器,ADO2.5以上版本的Windows,IIS,SQL Server的環境中。
為簡單起見,我們只選擇單價小於等於20美圓,庫存大於等於20,產品名稱小於等於6個字元的產品:
<% Dim objRecordset Set objRecordset = Server.CreateObject("ADODB.Recordset") objRecordset.open _ "SELECT PRoductName, UnitPrice, UnitsInStock " _ & "FROM Products " _ & "WHERE UnitPrice <= 20 " _ & "AND UnitsInStock >= 20 " _ & "AND LEN(ProductName) <= 6 " _ & "ORDER BY ProductName", _ "Provider=SQLOLEDB;" _ & "Data Source=SomeSQLServer;" _ & "Initial Catalog=Northwind;" _ & "User ID=MyUserName;" _ & "PassWord=MyPassword;" %>
現在,我們就用3種方式把我們得到的記錄集轉換成XML格式。
首先,我們可以遍歷整個記錄集,採用XML DOM(Document Object Model),建立XML節點樹:
<% Dim objXMLDOM, objRootNode, objNode Set objXMLDOM = Server.CreateObject("MSXML2.DOMDocument") Set objRootNode = objXMLDOM.createElement("xml") objXMLDOM.documentElement = objRootNode Do While NOT objRecordset.EOF Set objRowNode = objXMLDOM.createElement("row") Set objNode = objXMLDOM.createElement("ProductName") objNode.text = objRecordset.Fields.Item("ProductName").Value objRowNode.appendChild(objNode) Set objNode = objXMLDOM.createElement("UnitPrice") objNode.text = objRecordset.Fields.Item("UnitPrice").Value objRowNode.appendChild(objNode) Set objNode = objXMLDOM.createElement("UnitsInStock") objNode.text = objRecordset.Fields.Item("UnitsInStock").Value objRowNode.appendChild(objNode) objRootNode.appendChild(objRowNode) objRecordset.MoveNext Loop Set objNode = Nothing Set objRowNode = Nothing Set objRootNode = Nothing Set objRecordset = Nothing %>
現在,我們就得到了一個XML DOM物件。這種方法對於記錄集很大時效能並不理想,因為系統記憶體中要同時保存ADO記錄集物件和XML DOM物件。
第二個辦法,遍歷記錄集,直接產生XML字串本身:
<% Dim strXML strXML = "<xml>" objRecordset.MoveFirst Do While NOT objRecordset.EOF strXML = strXML & "<row>" strXML = strXML & "<ProductName>" _ & objRecordset.Fields.Item("ProductName").Value _ & "</ProductName>" strXML = strXML & "<UnitPrice>" _ & objRecordset.Fields.Item("UnitPrice").Value _ & "</UnitPrice>" strXML = strXML & "<UnitsInStock>" _ & objRecordset.Fields.Item("UnitsInStock").Value _ & "</UnitsInStock>" strXML = strXML & "</row>" objRecordset.MoveNext Loop strXML = strXML & "</xml>" Set objRecordset = Nothing %>
但是,以上兩種方法最大的缺陷是無法重複使用程式碼,我們把節點的名字都寫死了,如果我們進行不同欄位的查詢,我們還必須手動更改我們的程式碼,以滿足不同節點的需要。我們下面的方法將變得更加通用。
第三種方法:可重複使用的方法。
<% Dim strXML strXML = "<xml>" objRecordset.MoveFirst Do While NOT objRecordset.EOF strXML = strXML & "<row>" For Each varItem In objRecordset.Fields strXML = strXML _ & "<" & varItem.name & ">" _ & varItem.value _ & "</" & varItem.name & ">" Next strXML = strXML & "</row>" objRecordset.MoveNext Loop strXML = strXML & "</xml>" Set objRecordset = Nothing %>
更有效的方法,我們可以直接利用記錄集內建的save方法,它能夠自動地將記錄集的內容轉換成XML格式,我們調用save方法後,我們就可以立即釋放記憶體中的記錄集物件實例。 save方法有兩個參數:一個是XML要保存的地方,一個是指示符,標明資料以何種格式儲存。我們可以把資料保存成XML DOM物件(ADO STREAM物件),也可以直接儲存成asp RESPONSE對象,為通用起見,我們儲存成XML DOM,第二個參數用adPersistXML ADO常數。方法如下:
<% Const adPersistXML = 1 Dim objXMLDOM Set objXMLDOM = Server.CreateObject("MSXML2.DOMDocument.3.0") objRecordset.save objXMLDOM, adPersistXML Set objRecordset = Nothing %>
這種方法方便快捷,而且不容易出錯,對不同的查詢,也不用手動更改節點名字。但是,這種方法產生的XML不夠簡潔,看看它產生的結果:
<xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema"> <s:Schema id="RowsetSchema"> <s:ElementType name="row" content="eltOnly" rs:CommandTimeout="30"> <s:AttributeType name="ProductName" rs:number="1" rs:writeunknown="true"> <s:datatype dt:type="string" dt:maxLength="40" rs:maybenull="false"/> </s:AttributeType> <s:AttributeType name="UnitPrice" rs:number="2" rs:nullable="true" rs:writeunknown="true"> <s:datatype dt:type="number" rs:dbtype="currency" dt:maxLength="8" rs:precision="19" rs:fixedlength="true"/> </s:AttributeType> <s:AttributeType name="UnitsInStock" rs:number="3" rs:nullable="true" rs:writeunknown="true"> <s:datatype dt:type="i2" dt:maxLength="2" rs:precision="5" rs:fixedlength="true"/> </s:AttributeType> <s:extends type="rs:rowbase"/> </s:ElementType> </s:Schema> <rs:data> <z:row ProductName="Chai" UnitPrice="18" UnitsInStock="39"/> <z:row ProductName="Konbu" UnitPrice="6" UnitsInStock="24"/> <z:row ProductName="Tofu" UnitPrice="23.25" UnitsInStock="35"/> </rs:data> </xml>
ADO 自动产生的XML包含了schema信息,它描述这个XML里允许有什么节点和属性以及采用何种数据类型,而且数据节点也增加了名称空间。schema信 息在需要数据验证的地方或进行更复杂的处理或许很有用,但是,大多数情况下,我们使用的是瘦客户机,我们不需要schema信息。我们可以利用XSLT来 分离出我们想要的信息,去掉多余的信息。因此,我们编写下面的“ DataCleaner.xsl”:
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema"> <xsl:output omit-xml-declaration="yes"/> <xsl:template match="/"> <xsl:element name="xml"> <xsl:for-each select="/xml/rs:data/z:row"> <xsl:element name="row"> <xsl:for-each select="@*"> <xsl:element name="{name()}"> <xsl:value-of select="."/> </xsl:element> </xsl:for-each> </xsl:element> </xsl:for-each> </xsl:element> </xsl:template> </xsl:stylesheet>
这个XSLT具有可重用的特性,对于不同的查询结果都适用,下面就是如何使用这个XSLT的例子:
<% Dim strCleanXML, objXMLDOM_XSLT Set objXMLDOM_XSLT = CreateObject("MSXML2.DOMDocument") objXMLDOM_XSLT.load(Server.MapPath("DataCleaner.xsl")) strCleanXML = objXMLDOM.transformNode(objXMLDOM_XSLT) Set objXMLDOM = Nothing Set objXMLDOM_XSLT = Nothing %>
经过上面的处理以后,strClaenXML就是我们所想要的XML字符串了。
<xml> <row> <ProductName>Chai</ProductName> <UnitPrice>18</UnitPrice> <UnitsInStock>39</UnitsInStock> </row> <row> <ProductName>Konbu</ProductName> <UnitPrice>6</UnitPrice> <UnitsInStock>24</UnitsInStock> </row> </xml>
上面这种格式的XML字符串是我们经常见到的节点集的样式,如果您不想把字段处理成节点,而把它处理成属性节点,那么我们只需对DataCleaber.xsl稍加改动即可:
<?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema"> <xsl:output omit-xml-declaration="yes"/> <xsl:template match="/"> <xsl:element name="xml"> <xsl:for-each select="/xml/rs:data/z:row"> <xsl:element name="row"> <xsl:for-each select="@*"> <xsl:attribute name="{name()}"> <xsl:value-of select="."/> </xsl:attribute> </xsl:for-each> </xsl:element> </xsl:for-each> </xsl:element> </xsl:template> </xsl:stylesheet>
以下是采用了新样式的结果,它比用节点表示字段的长度要短的多了。传输起来速度会更快:
<xml> <row ProductName="Chai" UnitPrice="18" UnitsInStock="39"/> <row ProductName="Konbu" UnitPrice="6" UnitsInStock="24"/> </xml>
到此为止,我们介绍了从ADO 记录集得到XML格式数据的几种办法,也得到了最简化的字符串。但是有几个问题你仍然需要注意,有些字段值还有XML里不支持的字符,比如:"'6d267e5fab17ea8bc578f9e7e5e1570b&,象P&G宝洁公司的名称,Chef Anton's Gumbo Mix产品名字等,在做转换时要进行编码处理。在Microsoft ADO 2.6的SDK里有使用save方法时要注意的问题:1,save方法只对open Recordset起作用;2,不支持带有adVariant,adIDispatch,adIUnknown类型的字段的记录集的savw;3,当保存 分级的记录集( data shapes)有两个限制:不能保存参数化和含有未解决的更新的记录集。
为了更进一步提高性能,你可以把转换工作放 到COM/COM+组件中, ASP代码只进行数据的最终表现即可。把业务层、数据层和表现层分开,ASP只需要调用数据组件,数据组件调用数据库的存储过程,把结果转换成XML,最 后只把简单的XML字符环串回到ASP程序里,ASP就可以用XSLT把XML进行转换,把结果送到浏览器。
以上就是利用XSLT把ADO记录集转换成XML的内容,更多相关内容请关注PHP中文网(www.php.cn)!