• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • 在Microsoft Office中使用ADO.NET

    發表于:2007-05-25來源:作者:點擊數: 標簽:ADO.NETOfficemicrosoft使用
    XML Web Service !XML Web Service!XML Web Service 無處不在!當然,您早就知道這一點。但是,如果您沒有加入使用 XML Web Service 的行列,就無法讀懂有關 XML Web Service 的文章。親自用過后,我發現 XML Web Service 是極其有用的。 給我留下最深印象
      XML Web Service!XML Web Service!XML Web Service 無處不在!當然,您早就知道這一點。但是,如果您沒有加入使用 XML Web Service 的行列,就無法讀懂有關 XML Web Service 的文章。親自用過后,我發現 XML Web Service 是極其有用的。

      給我留下最深印象的是什么?主要有三點:

    • 創建 XML Web Service 非常容易。
    • 我的客戶和第三方可以使用 XML Web Service 迅速找到有用信息。
    • XML Web Service 配合 Microsoft? Office 一起使用非常容易。

      但是,我再次發現對構造集成的 Microsoft Office 和 XML Web Service 解決方案需求尚未得到滿足。我發現自己經常需要將已被序列化為 XML 并已通過 XML Web Service 傳輸的 ADO.NET 數據集應用到使用 Microsoft Office 創建的解決方案中。有這種需求的不止我一個,我在新聞組中看到有很多人都要求有完成這一任務的便捷方法。由于 Microsoft .NET 剛剛問世,因此 Microsoft Office 的當前版本不能提供現成的解決方案以使用 ADO.NET 數據。但是這也并非完全沒有可能。

      在本文中,我將介紹如何通過可以重復使用的方法將 XML Web Service 提供的 ADO.NET 數據集應用到 Microsoft Office 中。這里介紹的解決方案可以與 Microsoft Office XP 和 Microsoft Office 2000 配合使用。Microsoft Visual Basic? for Applications (VBA) 源代碼還要求具備 MSDN SOAP Developer Center中提供的 Microsoft SOAP Toolkit 3.0 和 Microsoft XML (MSXML) Core Services 4.0 庫。

      首先,我們需要查看已被序列化為 XML 的數據集的結構。然后,在了解了 XML 的結構之后,我們將討論兩種在 Microsoft Office 中使用這些數據的方法。

      獲得數據集

      首先,讓我們來看看我在文章一開始的評價中提到的第一點:創建 XML Web Service 的便捷性。在 Microsoft Visual Studio? .NET 中,我介紹了一個可以返回 ADO.NET 數據集的簡單函數。僅需添加 <WebMethod()> 屬性,我就可以立即將同樣的代碼轉換為 XML Web Service:

    Private sConnNwind As String = "Data Source=localhost;" & _
    "Initial Catalog=northwind;" & _
    "User ID={UserID};" & _
    "password={Password}"
    <WebMethod()> Public Function RunQuery() As DataSet
    Dim cn As SqlConnection = New SqlConnection(sConnNwind)
    Dim cmd As SqlCommand = New SqlCommand("SELECT * from Orders", cn)
    Dim da As SqlDataAdapter = New SqlDataAdapter()
    da.SelectCommand = cmd
    cn.Open()
    Dim dsAuthors As DataSet = New DataSet()
    da.Fill(dsAuthors)
    cn.Close()
    Return dsAuthors
    End Function

      Visual Studio .NET 使所有這一切變得如此便捷!我簡直無法想像如果編寫代碼先將其轉換為 XML 文檔,然后再轉換為 SOAP 消息以作為 XML Web Service 傳輸會多么繁瑣。不僅如此,我根本不想在 Visual Basic .NET 代碼上花費太多時間;這些概念在 MSDN 上隨處可見。對于這一代碼節選,您應該注意主要兩點:

    • 該函數可以運行來自羅斯文數據庫的查詢并返回數據集。
    • <WebMethod()> 屬性對該函數進行標記,使其作為 XML Web Service 可見。

      還需要順便提一下,數據集類似于 ADO Recordset 對象,但功能要強大得多。它可以將查詢的多個結果及其關系存儲在 DataSet 對象中,最重要的是,它可以將包含的數據序列化為 XML 流。

      同樣,當 RunQuery 函數被調用時,ADO.NET 會連接到羅斯文 Microsoft SQL Server? 數據庫,并將查詢結果檢索至 DataSet 對象。此時,函數即可返回數據集。.NET 能夠序列化數據集,并且 XML 流會被發送回調用者。已序列化的數據集類似于如下所示:

    <?xml version="1.0" encoding="utf-8"?>
    <DataSet xmlns="http://tempuri.org/WS_XML">
    <xs:schema id="NewDataSet" xmlns=""
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xs:element name="NewDataSet" msdata:IsDataSet="true">
    <xs:complexType>
    <xs:choice maxOclearcase/" target="_blank" >ccurs="unbounded">
    <xs:element name="Table">
    <xs:complexType>
    <xs:sequence>
    <xs:element name="OrderID" type="xs:int" minOccurs="0" />
    <xs:element name="CustomerID"
    type="xs:string" minOccurs="0" />
    <xs:element name="EmployeeID"
    type="xs:int" minOccurs="0" />
    <xs:element name="OrderDate"
    type="xs:dateTime" minOccurs="0" />
    <xs:element name="RequiredDate"
    type="xs:dateTime" minOccurs="0" />
    <xs:element name="ShippedDate"
    type="xs:dateTime" minOccurs="0" />
    <xs:element name="ShipVia" type="xs:int" minOccurs="0" />
    <xs:element name="Freight"
    type="xs:decimal" minOccurs="0" />
    <xs:element name="ShipName"
    type="xs:string" minOccurs="0" />
    <xs:element name="ShipAddress"
    type="xs:string" minOccurs="0" />
    <xs:element name="ShipCity"
    type="xs:string" minOccurs="0" />
    <xs:element name="ShipRegion"
    type="xs:string" minOccurs="0" />
    <xs:element name="ShipPostalCode"
    type="xs:string" minOccurs="0" />
    <xs:element name="ShipCountry"
    type="xs:string" minOccurs="0" />
    </xs:sequence>
    </xs:complexType>
    </xs:element>
    </xs:choice>
    </xs:complexType>
    </xs:element>
    </xs:schema>
    <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
    xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
    <NewDataSet xmlns="">
    <Table diffgr:id="Table1" msdata:rowOrder="0">
    <OrderID>10248</OrderID>
    <CustomerID>VINET</CustomerID>
    <EmployeeID>5</EmployeeID>
    <OrderDate>1996-07-04T00:00:00.0000000-05:00</OrderDate>
    <RequiredDate>1996-08-01T00:00:00.0000000-
    05:00</RequiredDate>
    <ShippedDate>1996-07-16T00:00:00.0000000-
    05:00</ShippedDate>
    <ShipVia>3</ShipVia>
    <Freight>32.38</Freight>
    <ShipName>Vins et alcools Chevalier</ShipName>
    <ShipAddress>59 rue de l'Abbaye</ShipAddress>
    <ShipCity>Reims</ShipCity>
    <ShipPostalCode>51100</ShipPostalCode>
    <ShipCountry>France</ShipCountry>
    </Table>
    <Table diffgr:id="Table2" msdata:rowOrder="1">
    <OrderID>10249</OrderID>
    <CustomerID>TOMSP</CustomerID>
    <EmployeeID>6</EmployeeID>
    <OrderDate>1996-07-05T00:00:00.0000000-05:00</OrderDate>
    <RequiredDate>1996-08-16T00:00:00.0000000-
    05:00</RequiredDate>
    <ShippedDate>1996-07-10T00:00:00.0000000-
    05:00</ShippedDate>
    <ShipVia>1</ShipVia>
    <Freight>11.61</Freight>
    <ShipName>Toms Spezialit?ten</ShipName>
    <ShipAddress>Luisenstr. 48</ShipAddress>
    <ShipCity>Münster</ShipCity>
    <ShipPostalCode>44087</ShipPostalCode>
    <ShipCountry>Germany</ShipCountry>
    </Table>
    </NewDataSet>
    </diffgr:diffgram>
    </DataSet>

      該 XML 序列化數據集包括兩個主要部分:

    • XML 架構(??s寫為 XSD)部分,其中包含有關 XML 文檔中數據的結構信息。
    • 第二部分實際上包含來自查詢的數據。正如您所看到的,本文檔中講述的 XML 序列化數據集是來自我們的 SQL Server 數據庫的自包含、可移植的數據表示形式。它包括表格結構、數據類型和元素中的數據。

      該信息對 Microsoft Office 用戶有用嗎?當然有用。Microsoft Office 完全是為了使數據和信息有用、相關并可操作。隨著 XML Web Service 在 Internet 和企業內部網絡上的不斷擴展,Microsoft Office 用戶會希望利用 XML Web Service 所提供的信息。我對 Microsoft Office 用戶真正欽佩的原因之一便是他們能夠在獲得原始數據后對其進行研究、壓縮、改變,或采取他們所需的任何方式對其進行處理,以運用這些數據來完成自己的工作。Microsoft Office 為用戶提供了對數據進行此類處理時所需的工具,而且最重要的是,我不用再編寫更多的代碼來解決問題了,因為這些工具可以更好地解決他們。

      其實,真正的原因是我想偷懶。我想用友好的 Microsoft Office 方式為用戶提供數據,然后讓用戶自己處理這些數據。

      了解該信息后,是否就可以在 Microsoft Office 的桌面上根據自己的需要重組這些數據呢?是的。我將在本文的后半部分向您介紹如何利用 Microsoft Excel 的內置方法來使用 XML 序列化數據集,以及如何完全靈活地運用使用 VBA 代碼的自定義解決方案通過任一 Office 應用程序做到這一點。



       不要做無謂的重復

      在本文開始,我曾提到過 Microsoft Office 沒有提供可以使用 XML 序列化數據集的現成解決方案。但是,Microsoft Excel 確實提供了一個與此非常相似的功能。從創建 Microsoft Office 解決方案時所積累的經驗中,您應該明白一件事情,那就是不要做無謂的重復。作為程序員,我們都有一種傾向:為要做的每一件事情編寫代碼。在使用 Microsoft Office 時,重要的是要學會問自己一個簡單的問題,“有沒有可以利用的內置功能,使我不用編寫代碼就可以更迅速地達到我的目的?”對于我們試圖解決的問題,Microsoft Excel 提供了一個我們可以利用的功能,稱為 Web 查詢。Web 查詢有其局限性,但是在處理 XML Web Service 的很多情況下都非常有用,并且在我看來,它是經常被忽略的一種重要功能。我們來快速回顧一下 Microsoft Excel Web 查詢功能的優點和缺點。

      在本文后半部分中,我們將利用可以公開使用的 Web 服務。請花幾分鐘的時間用您的瀏覽器運行一下該 XML Web Service。它會為 Fabrikam.com(Fabrikam.com 是建立在 Microsoft Office 之上的示例應用程序;返回對當前打開的訂單的查詢。您在瀏覽器中看到的 XML 是序列化數據集,形式類似于以前 SQL Server 羅斯文數據庫中的數據集。

      讓我們在 Microsoft Excel Web 查詢中運用這種 Web 服務。要進行此操作,請執行以下步驟:

    • 啟動 Microsoft Excel。
    • 在“數據”菜單上,指向“導入外部數據”并單擊“新建 Web 查詢”。
    • 顯示“新建 Web 查詢”對話框。
    • 在“地址”列表中,鍵入 http://services.fabrikam.com/OWSISample/Order.asmx/OpenOrders 并單擊“轉到”。圖 1 顯示了您將看到的內容。



      圖 1:預覽 Fabrikam OpenOrders XML Web Service 的“新建 Web 查詢”對話框。

    • 單擊“導入”。
    • 然后系統會詢問您在何處插入 Web 查詢數據。在空白工作表上選擇任一單元格,然后單擊“確定”。
    • Web 查詢將運行并插入結果,如圖 2 所示。

    圖 2:插入工作表中的 Web 查詢結果。

      正如您所看到的,我們無需任何代碼便可輕松地將 XML Web Service 的結果導入 Excel。我已經多次使用過這種方法,發現它是一種相當可靠的技術。Excel 中的 Web 查詢技術出奇地靈活;要了解可用的配置選項,請參見圖 3。我比較喜歡的功能是它能夠基于某些參數更新單元格。例如,您可以讓 Web 查詢按照您指定的時間間隔(分鐘)或在首次打開工作簿時自我更新。這樣可以確保您總能具備最新的信息。

    圖 3:“Web 查詢屬性”對話框。

      但是,Web 查詢也有一些缺點。首先,您可能會注意到 Excel 中的列標題不是很明確。Excel 配有內置的 XML 轉換器,專門用于導入任意 XML 并將其轉換為電子表格。Excel 采用的方法可以通用,因為它沒有關于所加載 XML 的結構和用途的任何線索。在我們的例子中,我們所使用的 XML 不是任意的;其格式或架構都是大家所熟悉的。這意味著,我們使用基于通用布局的 Web 查詢時,XML 的所有格式和其他元素在 Excel 中對于我們來說都是有用的。

      此外,Excel 目前無法處理 XSD 數據類型。因此,當我們運行 Web 查詢時,很多數據類型都無法按照我們所希望的方式被轉換或處理。例如在圖 2 中,您可以注意到數據欄中包含類似 2002-07-19T10:53:36.000000004:00 的數據。XSD 以 ISO 8601 數據格式顯示數據。正如您所看到的,Excel 無法識別此數據格式,并將其作為字符串來處理。

      最后,對于能夠處理 XML 的 Web 查詢來說,其最大的缺陷便是僅在 Microsoft Excel 2002 中可用。因此,可以消除這些局限性并可以在任意 Microsoft Office 應用程序中使用的技術將是非常有用的。在我講述如何通過 VBA 代碼做到這一點之前,請采納我的建議:如果您還不了解 Web 查詢,最好先花一點時間來進一步了解它。對于無需編寫代碼就可以使用 XML Web Service 來說,Web 查詢的確很有幫助。有關 Web 查詢的詳細信息,請參閱 Charles Maxson 的文章“Well-kept Secret: Excel's Web Queries Enable You to Populate Worksheets from Web Sites”。


      擴展您自己的解決方案

      很明顯,我們要再次提及需要將來自 XML Web Service 并已序列化的 ADO.NET 數據集作為 XML 應用到任意 Microsoft Office 應用程序中的問題。我們希望通過可以輕松處理這些數據的方法使用這些數據,我們還希望得到源代碼以便完全控制處理過程。

      以下解決方案可以用于任意啟用 VBA 的應用程序,也可以通過 Microsoft Visual Basic 6.0 使用。要使用此解決方案,需要執行以下步驟:

    • 從 XML Web Service 中檢索 XML。
    • 將 XML 分析到 VBA Array 對象中。
    • 將數據插入 Office 應用程序。
      步驟 1:檢索 XML

      首先,我們需要從 XML Web Service 中檢索序列化為 XML 的 ADO.NET 數據集。這在我們的解決方案中是最容易的一個步驟。從 Microsoft Office 應用程序(包括 Word、Excel 和 Microsoft PowerPoint? 等)之一的 VBA 集成開發環境 (IDE) 中,我們需要為以下兩個庫設置引用:

    • Microsoft Soap Type Library v3.0
    • Microsoft XML v4.0

      如果您還沒有上面這兩個庫,可以去免費下載。以下代碼將運行 XML Web Service,并將結果檢索到 MSXML IXMLDOMNodeList 對象中:

    Public Function ParseDataSet(ByRef xdlXSDFromSoapClient As Dim sc As MSSOAPLib30.SoapClient30
    Dim xdl As MSXML2.IXMLDOMNodeList
    Set sc = New MSSOAPLib30.SoapClient30
    sc.MSSoapInit "http://services.fabrikam.com/OWSISample/Order.asmx?wsdl"
    Set xdl = sc.OpenOrders

      首先,我們創建一個 SoapClient30 對象。該 SoapClient30 對象是包含在 Microsoft SOAP Toolkit 3.0 中的實用程序對象。它封裝了所有連接到遠程 XML Web Service 所必須的邏輯和通道,執行 Web 方法,并向客戶返回 XML 信息。要做到這一點,必須將 XML Web Service 的 Web 服務說明語言 (WSDL) 文件的引用傳遞給 MSSoapInit 屬性。這能夠使 SoapClient30 對象知道可以使用何種服務和方法。一旦 SoapClient30 對象被初始化,我們便可以調用由 XML Web Service 提供的任意方法:

      Set xdl = sc.OpenOrders

      在我們的例子中,我們調用了 OpenOrders 方法,它可以返回在本文前半部分中看到的 XML 結果。Microsoft SOAP Toolkit 3.0 使這些變得很容易;它僅用了四行代碼。請注意,XML Web Service 所回應的是 IXMLDOMNodeList 對象。IXMLDOMNodeList 對象是 MSXML 4 庫中的對象,含有 XML 的片段,并被顯示為 IXMLDOMNode 對象。這便是令人感興趣的地方。IXMLDOMNodeList 對象包含兩個 XML 片段的節點。第一個節點包含 XML 架構(定義數據結構和數據類型),第二個節點包含我們的實際數據。這對我們來說非常方便,現在我們只需兩個節點對象便可以先分析 XML 的結構,然后從第二個節點中分析出數據。

      步驟 2:將 XML 分析到 VBA Array 對象中

      在講述如何將 XML Web Service 返回的 XML 分析到數組中之前,我需要解釋一下為什么要將數據分析到數組中,而不分析到某些其他類似 ADO Recordset 對象的內存內表示形式或 VBA 類型的結構中。最開始時,我打算支持其他內存內表示形式。我首先從數組開始,因為數組是支持 VBA 的應用程序中的共同特性。數組簡單、快速,并且沒有 ADO 之類的外部相關性。我推斷在數組邏輯可以運行后,應該能夠很容易地修改代碼以滿足更高的要求。但是事實是,數組原來非常靈活,并且可以游刃有余地滿足我的所有需要。不僅如此,您可以清楚地發現通過修改這些代碼還可以輕松地創建 ADO 記錄集或其他東西。

      以下代碼用于將 XML 分析到數組:

    IXMLDOMNodeList, _
    ByVal sTableName As String, _
    ByVal bReturnFieldHeaders As Boolean) As Variant
    Dim xdd As MSXML2.DOMDocument40
    Dim xdlStructure As MSXML2.IXMLDOMNodeList
    Dim xdlRows As MSXML2.IXMLDOMNodeList
    Dim lcntRows As Long
    Dim lctrRow As Long
    Dim lcntFields As Long
    Dim saFieldDefinitions() As String ' 用于存儲字段名和字段 _
    ' 數據類型的數組。
    Dim lctrFieldDef As Long
    Dim iRowHeader As Long
    Dim vArray() As Variant ' 由函數返回的表格數據的數組。
    Dim iCntUbound As Integer
    Dim iCtr As Integer
    Dim sNodeName As String
    Dim xdlFields As IXMLDOMNodeList
    Dim xdnField As IXMLDOMNode
    Dim iNode As Integer
    Dim sDataSetNameSpace As String

    Set xdd = New MSXML2.DOMDocument40
    With xdd
    ' 加載字段定義 XML。
    .async = False
    .preserveWhiteSpace = True
    .setProperty "SelectionNamespaces", _
    "xmlns:xs='http://www.w3.org/2001/XMLSchema'"
    .loadXML xdlXSDFromSoapClient.Item(0).XML
    Set xdlStructure = xdd.selectNodes("http://xs:element[@name='" & _
    sTableName & _
    "']/xs:complexType/xs:sequence/xs:element")
    ' 導入字段定義數組。
    lcntFields = xdlStructure.Length - 1 ' 基于零。
    If lcntFields = -1 Then
    MsgBox "指定的表格不存在。"
    Exit Function
    End If
    End With

    ReDim saFieldDefinitions(lcntFields, 1) As String
    For lctrFieldDef = 0 To lcntFields
    With xdlStructure.Item(lctrFieldDef).Attributes
    saFieldDefinitions(lctrFieldDef, 0) = .getNamedItem("name").Text
    saFieldDefinitions(lctrFieldDef, 1) = .getNamedItem("type").Text
    End With
    Next

    ' 開始建立數組。
    With xdlXSDFromSoapClient.Item(1).FirstChild.Attributes
    sDataSetNameSpace = .getNamedItem("xmlns").Text
    End With

    Set xdd = New MSXML2.DOMDocument40
    With xdd
    .async = False
    .preserveWhiteSpace = True
    .loadXML xdlXSDFromSoapClient.Item(1).XML
    If sDataSetNameSpace = "" Then
    Set xdlRows = xdd.selectNodes("http://" & sTableName)
    Else
    .setProperty "SelectionNamespaces", "xmlns:df='" & _
    sDataSetNameSpace & "'"
    Set xdlRows = xdd.selectNodes("http://df:" & sTableName)
    End If
    End With

    lcntRows = xdlRows.Length - 1 ' 從 0 開始索引
    If lcntRows = -1 Then
    MsgBox "XSD Web Service returned no records", vbCritical, "No Data"
    Exit Function
    End If

    ' 添加行標題(可選)。
    If bReturnFieldHeaders = True Then
    ' 添加標題行。
    ReDim vArray(lcntRows + 1, lcntFields) As Variant
    iRowHeader = 1 ' 添加行標題。
    For lctrFieldDef = 0 To lcntFields
    vArray(0, lctrFieldDef) = _
    Replace(saFieldDefinitions(lctrFieldDef, 0), _
    "_x0020_", " ")
    Next
    Else
    ' 無標題行。
    ReDim vArray(lcntRows, lcntFields) As Variant
    iRowHeader = 0 ' 無行標題
    End If

    ' 向數組添加行數據。
    iCntUbound = UBound(saFieldDefinitions)
    For lctrRow = 0 To lcntRows

    Set xdlFields = xdlRows.Item(lctrRow).childNodes

    For Each xdnField In xdlFields
    ' 循環將索引放到字段名和數據類型中。
    sNodeName = xdnField.nodeName
    For iCtr = 0 To iCntUbound
    If saFieldDefinitions(iCtr, 0) = sNodeName Then
    iNode = iCtr
    Exit For
    End If
    Next

    Select Case saFieldDefinitions(iNode, 1)
    Case "xs:int"
    vArray(lctrRow + iRowHeader, iNode) = CLng(xdnField.Text)
    Case "xs:integer"
    vArray(lctrRow + iRowHeader, iNode) = CVar(xdnField.Text)
    Case "xs:long"
    vArray(lctrRow + iRowHeader, iNode) = CVar(xdnField.Text)
    Case "xs:date"
    vArray(lctrRow + iRowHeader, iNode) = _
    ConvertISO8601DateFormatToVBDateTime(xdnField.Text)
    Case "xs:dateTime"
    vArray(lctrRow + iRowHeader, iNode) = _
    ConvertISO8601DateFormatToVBDateTime(xdnField.Text)
    Case "xs:double"
    vArray(lctrRow + iRowHeader, iNode) = CDbl(xdnField.Text)
    Case "xs:short"
    vArray(lctrRow + iRowHeader, iNode) = CInt(xdnField.Text)
    Case "xs:float"
    vArray(lctrRow + iRowHeader, iNode) = CSng(xdnField.Text)
    Case "xs:boolean"
    vArray(lctrRow + iRowHeader, iNode) = CBool(xdnField.Text)
    Case "xs:byte"
    vArray(lctrRow + iRowHeader, iNode) = CInt(xdnField.Text)
    Case "xs:time"
    vArray(lctrRow + iRowHeader, iNode) = _
    ConvertISO8601DateFormatToVBDateTime(xdnField.Text)
    Case Else
    vArray(lctrRow + iRowHeader, iNode) = xdnField.Text
    End Select
    Next
    Next
    ParseDataSet = vArray
    End Function

    該 ParseDataSet 函數要求三個參數:

    參數 說明
    xdlXSDFromSoapClientIXMLDOMNodeList 對象) SoapClient30 對象中返回的 IXMLDOMNodeList 對象如本文前面章節中所述。
    sTableNameString 值) 從 XML Web Service 返回的 XML 中使用的唯一表名稱。
    注意:此參數(例如 XML)區分大小寫。
    bReturnFieldHeadersBoolean 值) 如果字段名作為數組中的第一行被返回則為 True。

      此例程相當長,但是有一定的原因。最初,我曾把此函數拆分為三個獨立的函數。但是我發現,由于讀取整個 XML 文檔對象模型 (DOM) 需要循環很多次,因此從函數外部進行調用時性能會受到影響?;谶@一原因,將內聯的所有代碼集中在一個函數中會更加合理。這與使用獨立的函數相比,可以將性能提高大約三倍。

      如果您曾經分析過 XML,那么當您查看 ParseDataSet 函數的代碼時便會發現,這些代碼類似于 MSXML 分析器。例程的第一部分會通過 XML 架構,以獲取 ADO.NET 數據集的字段名和數據類型。如果程序已選擇在數組的第一行中返回字段名,此信息將非常重要。它還可以用于將 XML 字符串數據轉換為相應的 VBA 數據類型。

      代碼的第二部分實際將按記錄逐個讀取 XML DOM,向數組中提取數據。在代碼的最后部分,您會發現一個很長的 Select Case 語句。這個 Select Case 語句將從 XML 架構檢查字段的數據類型,并強制執行從 XML 字符串型數據向相應 VBA 數據類型的轉換。如果我們不進行此操作,XML 中的所有整數都將在數組中顯示為字符串;但是我們希望這些數據真正顯示為整數。這同樣適用于所有其他數據類型。

      該 Select Case 語句還會為 ConvertISO8601DateFormatToVBDateTime 函數添加標注。這是例外情況,其中 ParseDataSet 函數將調用外部例程。轉換 ISO 8601 數據格式的邏輯相當繁瑣,因此將它分離出來更為合理。如果 XML 含有數據字段,該例程確實會對處理時間產生一些影響,但對于整體來說是可以忽略不計的。下面是 ConvertISO8601DateFormatToVBDateTime 函數:

    Public Function ConvertISO8601DateFormatToVBDateTime(ByRef vData As Variant) As Variant
    Dim lMonthSep As Long ' 月份分隔符位置。
    Dim lDaySep As Long ' 日期分隔符位置。
    Dim lMinutesSep As Long ' 分鐘分隔符位置。
    Dim sDt As String
    Dim sTm As String

    lMonthSep = InStr(1, vData, "-", vbBinaryCompare)
    lDaySep = InStr(lMonthSep + 1, vData, "-", vbBinaryCompare)

    If lMonthSep > 0 Then
    sDt = Mid(vData, lMonthSep + 1, 2) & "/" & _
    Mid(vData, lDaySep + 1, 2) & "/" & _
    Left(vData, lMonthSep - 1)
    End If

    ' 提取時間。
    lMinutesSep = InStr(1, vData, ":", vbBinaryCompare)

    If lMinutesSep > 0 Then
    sTm = Mid(vData, lMinutesSep - 2, 8)
    End If

    ConvertISO8601DateFormatToVBDateTime = CDate(sDt & " " & sTm)

    End Function

      ConvertISO8601DateFormatToVBDateTime 函數將 ISO 8601 數據格式分解為它的組成部分,然后再將這些數據重組為適當的 VBA 數據。例如,我們前面提到過的數據 2002-07-19T10:53:36.000000004:00 在轉換后會顯示為 07/19/2002 10:53 AM。

      對于絕大部分來說,將 XML 分析到數據中是此解決方案中最難的一部分。ParseDataSet 函數在將已序列化為 XML 的 ADO.NET 數據分析到數組的過程中負責進行判斷。我們如何使用該函數?現在,讓我們對用來調用 XML Web Service 的代碼進行擴展以分析數據:

    Dim sc As MSSOAPLib30.SoapClient30
    Dim xdl As MSXML2.IXMLDOMNodeList
    Dim vDataSet As Variant

    Set sc = New MSSOAPLib30.SoapClient30
    sc.MSSoapInit "http://services.fabrikam.com/OWSISample/Order.asmx?wsdl"
    Set xdl = sc.OpenOrders
    vDataSet = ParseDataSet(xdl, "Table", True)

      我們僅添加了兩行代碼:

    dim vDataSet As Variant
    vDataSet = ParseDataSet(xdl, "Table", True)

      我們首先創建了 Variant 類型的變量。然后,調用在 IXMLDOMNodeList 對象中傳遞的 ParseDataSet 函數以及我們希望從數據集返回的表名稱,同時 True 表示字段標題名應該被放入數組的第一行。此時,您可能會有疑問:ParseDataSet 函數不返回數組嗎?我們為什么要把 ParseDataSet 函數的返回值指定為 Variant?Variant 數據類型確實有很多缺陷,但是它是一個非常有用的數據類型。我們在此處使用的這種方法稱為 Variant 數組。實際上您可以創建一個數組并把它分配給 Variant 變量。這樣我們便具備了擁有該數組的變量,而且無需知道數組所需的大小,因為直到返回真正的數據集時我們才能了解這一信息。Variant 數組的使用方法與任何其他數組相同。您可以使用 vDataSet(0,0) 表示形式以及任何其他可以識別數組的函數(例如 UPPER 和 LOWER)從數組中檢索元素。

      具備可重復使用的例程 ParseDataSet 和 ConvertISO8601DateFormatToVBDateTime 后,我們便可以僅通過幾行代碼來分析返回 XML 序列化數據集的 XML Web Service 的結果。我曾經把這兩個函數捆綁在一個稱為 basWebServices.bas 的模塊中,您可以將其導入到您的 VBA 項目中。basWebServices.bas 模塊包含在下載的文章中。

      作為本步驟的結束,我再談幾個有關這些例程的問題。您可能會認為這些例程是不完美的。我已經在很多實例中測試過代碼,發現在如何將數據集序列化為 XML 這一點上,.NET 是非常靈活的。我曾經通過包含單個表和多個表的 XML 序列化數據集測試此代碼。我當然知道此代碼目前尚不支持嵌套表,因為我還沒有發現在 Microsoft Office 解決方案中有需要使用嵌套表的情況。因此,當 .NET 開發者偏離了從 XML Web Service 中返回數據集的默認機制,或數據集中包含復雜的表層次結構時,您就需要修改源代碼。但是擁有源代碼非常有益,因為它給您提供了更大的靈活性。


      步驟 3:用數組進行某些操作

      我曾說過步驟 1 很容易;步驟 3 則更加容易?,F在我們已將 ADO.NET 數據集分析到數組中,可以利用它在 Office 中進行任何操作。以下代碼是對我們一直在使用的示例的擴展。它從 XML Web Service 中檢索 XML 并對其進行分析,然后將其插入 Excel 的當前電子表格中:

    Dim rngData As Range
    Dim sc As MSSOAPLib30.SoapClient30
    Dim xdl As MSXML2.IXMLDOMNodeList
    Dim vDataSet As Variant

    ' 運行 XML Web Service 并將響應分析到數組中。
    Set sc = New MSSOAPLib30.SoapClient30
    sc.MSSoapInit "http://services.fabrikam.com/OWSISample/Order.asmx?wsdl"
    Set xdl = sc.OpenOrders
    vDataSet = ParseDataSet(xdl, "Table", True)

    ' 將數組作為格式化的網格插入。
    Set rngData = ActiveCell.Resize(UBound(vDataSet, 1) + 1, UBound(vDataSet, 2) + 1)
    rngData = vDataSet
    ActiveCell.AutoFilter
    Selection.AutoFormat Format:=xlRangeAutoFormatList2, Alignment:=True

      這是 Excel 最吸引我的原因之一。您可以將已為同樣大小的數組分配的 Range 對象直接分配到電子表格中。請注意 rngData = vDataSet 一行。就是這么簡單!為達到這個目的,我利用 AutoFilter 功能進行了一些改進以使它看起來更好,這樣用戶便可以深化數據并對數據應用自動格式。圖 4 顯示了結果。請將此結果與圖 2 中 Web 查詢所獲得的結果進行比較。

    圖 4:通過自定義 VBA 代碼插入到 Excel 中的 XML Web Service 數據。

      在 Word 中達到同樣目的會稍微復雜一點,因為 Word 中沒有可以將數組插入文檔的裝置。同時,遍歷數組的功能也尚未完善。以下代碼可以在 Word 中完成與在 Excel 中執行的相同任務:

    Private Sub InsertArrayAsWordTable()

    Dim sc As MSSOAPLib30.SoapClient30
    Dim xdl As MSXML2.IXMLDOMNodeList
    Dim vDataSet As Variant
    Dim nRows As Integer
    Dim nRowCount As Integer
    Dim nColumns As Integer
    Dim nColumnCount As Integer
    Dim sRow As String

    ' 運行 XML Web Service 并將響應分析到數組中。
    Set sc = New MSSOAPLib30.SoapClient30
    sc.MSSoapInit "http://services.fabrikam.com/OWSISample/Order.asmx?wsdl"
    Set xdl = sc.OpenOrders
    vDataSet = ParseDataSet(xdl, "Table", True)

    ' 將數組作為格式化的表格插入。
    nRows = UBound(vDataSet, 1)
    nColumns = UBound(vDataSet, 2)

    Selection.Collapse wdCollapseStart

    Options.Pagination = False
    For nRowCount = 1 To nRows
    For nColumnCount = 1 To nColumns
    sRow = sRow & vDataSet(nRowCount - 1, nColumnCount - 1)
    If nColumns <> nColumnCount Then
    sRow = sRow & vbTab
    End If
    Next
    sRow = sRow & vbCrLf
    Next

    With Selection
    .InsertAfter sRow
    .ConvertToTable Separator:=vbTab
    With .Tables(1)
    .AutoFitBehavior (wdAutoFitContent)
    .AutoFormat Format:=wdTableFormatList2
    End With
    .Collapse wdCollapseStart
    End With
    Options.Pagination = True

    End Sub

      InsertArrayAsWordTable 函數可以檢索 XML Web Service 數據并對其進行分析,然后循環讀取數組,以將文本作為制表符分隔字符串插入 Word。最后,使用 ConvertToTable 方法將字符串轉換為表格。就象使用 Excel 一樣,我們需要應用少量格式來改進其顯示形式。圖 5 顯示了結果。

    圖 5:通過自定義 VBA 代碼插入到 Word 中的 XML Web Service 數據。

      小結

      我所介紹的解決方案非常簡單,并可以有效地在 Microsoft Office 中順利顯示 ADO.NET 數據集。因此,用戶就可以隨心所欲地使用數據。

      最后要注意的是,不要向客戶端返回過多數據。我們發現,XML Web Service 通常很少會返回上百條記錄,這些記錄可以被迅速分析并插入 Microsoft Office。但是,當返回上千條記錄時,性能會受到影響。您肯定會想到通過線路傳輸大量數據時就會發生這種情況。Microsoft Office 處理數據所需的處理時間是容易忽視的問題,也是 Microsoft Office 文檔的實際局限性。例如,Microsoft Excel 的每張工作表中可以包含 65,000 行。我們確實曾經看到過用戶想向工作表中返回更多數據的情況。這使我們想起一句著名的格言:我們永遠不需要超過 640 KB 的 RAM。誰又曾想到我們可能會在工作表中需要超過 65,000 行呢?我肯定不會!

    原文轉自:http://www.kjueaiud.com

    評論列表(網友評論僅供網友表達個人看法,并不表明本站同意其觀點或證實其描述)
    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>