XML (Extensible Markup Language: eXtensible Markup Language) は真のプラットフォーム独立性を備えているため、徐々にデータ送信の主要なメディアになりつつあります。 XML は自己記述言語であり、データ自体にはメタデータ、つまりデータ自体に関する情報がすでに含まれています。例: 「Mencius Chapter 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 データを受信し、それを上記の例のスタイルに解析したら、XSLT (eXstensible Stylesheet Language Transformations) を通じてさまざまな表現に変換できます。データ送信に XML データ形式を使用すると、アプリケーション コードの作成作業がよりシンプルかつ簡単になり、優れたスケーラビリティが得られます。
次に、データを変換する方法を見てみましょう。この例は Microsoft Windows 2000、IIS5、MSXML3、および ADO2.6 で作成されており、サンプル データは Microsoft SQL Server7.0 に付属の Northwind サンプル データベースを使用しています。 XML をサポートする SQL Server2000 の代わりに SQL Server7 が使用される理由は、SQL Server2000 のように XML データ ソースをサポートするだけではなく、さまざまな種類のデータ ソースから取得したレコード セットを処理することを目的としているためです。 ADO が使用されるのは、さまざまな形式があり、さまざまな種類のデータ ソースを処理できるためです。XML は、迅速に送信して解析できるためです。ただし、この例の処理方法は、Microsoft 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;" %>
さて、取得したレコードセットを XML 形式に変換するには 3 つの方法を使用します。
まず、レコード セット全体を走査し、XML DOM (ドキュメント オブジェクト モデル) を使用して、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 オブジェクトをシステム メモリに同時に格納する必要があるため、レコードセットが大きい場合、このメソッドのパフォーマンスは理想的ではありません。
2 番目の方法は、レコード セットを走査し、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 %>
ただし、上記 2 つの方法の最大の欠点は、コードを再利用できないことです。ノードの名前を書き留めています。異なるフィールドに対して For クエリを実行する場合は、異なるノードのニーズに合わせてコードを手動で変更する必要もあります。以下のアプローチはより一般的になります。
3 番目の方法: 再利用可能な方法。
<% 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 メソッドを直接使用することで、save メソッドを呼び出した後、レコード セットの内容を XML 形式に自動的に変換できます。のメモリ Recordset オブジェクト インスタンスを直ちに解放します。 save メソッドには 2 つのパラメータがあります。1 つは XML が保存される場所であり、もう 1 つはデータが保存される形式を示すインジケータです。データは XML DOM オブジェクト (ADO STREAM オブジェクト) として保存することも、ASP RESPONSE オブジェクトとして直接保存することもできます。ここでは、一般性を考慮して XML DOM として保存し、2 番目のパラメーターに 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里不支持的字符,比如:"'< >&,象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)!