【问题标题】:Access VBA - how to download XML file and enter its data into a recordsetAccess VBA - 如何下载 XML 文件并将其数据输入到记录集中
【发布时间】:2011-10-28 19:15:34
【问题描述】:

我从网站获取一个 XML 到一个字符串 strXML。 然后我创建一个 XML DOM 文档:

    Dim xmlDoc As MSXML2.DOMDocument
    Dim xmlElement As MSXML2.IXMLDOMElement
    Dim xmlNode As MSXML2.IXMLDOMElement

    Set xmlDoc = New MSXML2.DOMDocument

    xmlDoc.loadXML (strXML)
    DisplayNode xmlDoc.childNodes

现在 DisplayNode 是一种递归方法,它为 XML 数据中的每一行调用自身:

Public Sub DisplayNode(ByRef Nodes As MSXML2.IXMLDOMNodeList)
Dim xNode As MSXML2.IXMLDOMNode

For Each xNode In Nodes
  If xNode.nodeType = NODE_TEXT Then
    Debug.Print xNode.parentNode.nodeName & " = " & xNode.nodeValue
  Else
    If xNode.parentNode.nodeName = "data" Then Debug.Print "*** NEW RECORD ***"
  End If

  If xNode.hasChildNodes Then
     DisplayNode xNode.childNodes
     Debug.Print "> recursive call - next field<"
  End If

Next xNode

End Sub

这里的问题是如何将递归循环中的 XML 数据输入到记录中。如果它只是一个普通的循环,那会很容易,但是递归循环不能保持卡车正在输入哪个字段和哪个记录,因为它不断地传递它的参数。

我现在可以看到的一种方法是创建一个包含两个字符串的对象集合。我可以将所有数据节点添加到此集合中,然后使用循环将数据从集合中移动到记录集中。

但是,我想知道是否可以在不使用递归方法而仅使用普通循环的情况下读取 XML 字符串,或者是否可以使用不同的方式将自定义 XML 文件/字符串加载到记录集中。

这是 DisplayNode 的输出:

*** NEW RECORD***
EVENTID = 75098
> recursive call <
DESCRIPTION = Pack
> recursive call <
NAME = John Smith
> recursive call <
CUSTOMERID = 37684
> recursive call <
TRADER = MY COMPANY
> recursive call <
ADDRESS = Flat A
SOUTHILL PARK
LONDON
> recursive call <
> recursive call <
*** NEW RECORD***
.
.
.
repeats

编辑: 显然,可以在递归调用之间传递对记录集的引用,并且记录集将保留其状态,因此可以逐个输入字段并保存记录。请参阅下面的完整解决方案。

【问题讨论】:

  • 如果您想将此数据放入(表格)记录集中,那么它可能也是“表格”(即没有深度嵌套)?如果是这种情况,跳过递归并使用几个嵌套循环来处理它会容易得多。格式是预先确定的,还是您尝试处理任何 XML?
  • 那么您不需要递归,将数据放入记录集更容易...您可以发布 XML 示例吗?
  • 谢谢蒂姆,但没必要,我找到了一种以足够简单的方式使用递归模式的方法。我稍后会发布我的解决方案。

标签: ms-access vba ms-access-2007


【解决方案1】:

您可以使用MSXML2.IXMLDOMNode.selectNode() 通过 xpath 表达式显式选择节点吗?这样,您就可以跟踪从外部输入的字段/记录。

【讨论】:

    【解决方案2】:

    这是一个可行的解决方案。下面的方法需要在将显示 XML 数据的访问表单中。表单中的文本字段应设置为它们的“控制源”与添加到 ADODB 记录集中的字段名称相同。

    Private Sub GetXMLdata()
     On Error GoTo ErrorHandler
    
    '************************************************************
    'CREATE AN ADODB RECORDSET - this recordset is in memory only it does not create a table in the database file
    'This requires a reference addedd in TOOLS > References, Microsfot ActiveX Data Object , the latest version...
    '************************************************************
    
     Dim rs As ADODB.Recordset
     Dim fld As ADODB.field
     Dim strXML As String
    
    
        Set rs = New ADODB.Recordset
        With rs
            .Fields.Append "EventID", adVarChar, 15, adFldMayBeNull
            .Fields.Append "JobDescription", adVarChar, 255, adFldMayBeNull
            .Fields.Append "FullName", adVarChar, 100, adFldMayBeNull
            .Fields.Append "CustomerID", adVarChar, 15, adFldMayBeNull
            .Fields.Append "CustomerAddress", adVarChar, 255, adFldMayBeNull
            .Fields.Append "Town", adVarChar, 64, adFldMayBeNull
            .Fields.Append "PostCode", adVarChar, 20, adFldMayBeNull
            .CursorType = adOpenKeyset
            .CursorLocation = adUseClient
            .LockType = adLockPessimistic
            .Open
        End With
    
    '**********************************************************
    'DOWNLOAD XML DATA 
    '**********************************************************
    
    
        Dim obj As MSXML2.ServerXMLHTTP
        Set obj = New MSXML2.ServerXMLHTTP
    
        bj.Open "GET", "http://www.myserver.com/mydata.xml", False
        'in case you are sending a form *POST* or XML data to a SOAP server set content type
        obj.setRequestHeader "Content-Type", "text/xml"    
        obj.send
    
        Dim status As Integer
        status = obj.status
    
        If status >= 400 And status <= 599 Then
            Debug.Print "Error Occurred : " & obj.status & " - " & obj.statusText
        End If
    
    
       '********************************************************** 
       'CREATE XML DOM DOCUMENT  
       '**********************************************************   
    
        Dim xmlDoc As MSXML2.DOMDocument
        Dim xmlElement As MSXML2.IXMLDOMElement
        Dim xmlNode As MSXML2.IXMLDOMElement
    
        Set xmlDoc = New MSXML2.DOMDocument
    
        xmlDoc.loadXML (obj.responseText)
    
    
    '**********************************************************
    'LOAD XML DATA INTO THE RECORDSET 
    '********************************************************** 
    
        LoadNodesIntoRs xmlDoc.childNodes, rs, 0
    
        If rs.recordCount > 0 Then
    
            rs.Update
    
        'BOUND THIS RECORDSET TO THE FORM
            Set Me.Recordset = rs
    
            End If
    
        Exit Sub
    
    
    ErrorHandler:
    
        MsgBox Err.Description
    
    End Sub
    

    下面的方法将字段一一输入到传递的记录集中。因为 MSXML2 似乎跳过了像 &lt;something&gt;&lt;/something&gt; 这样的空标签,每个带有数据的标签名称都需要按名称检查并输入到适当的记录集字段中。

    Public Sub LoadNodesIntoRs(ByRef nodes As MSXML2.IXMLDOMNodeList, rs As ADODB.Recordset, recordCount As Integer)
        Dim xNode As MSXML2.IXMLDOMNode
        Dim fieldIndex As Integer
    
        For Each xNode In nodes
            If xNode.nodeType = NODE_TEXT Then
                'a field - actual data
            'note that MSXML2 will skip any node which contain no data like <COMPANY></COMPANY>
    
                Select Case xNode.parentNode.nodeName
                    Case "EVENTID"
                        fieldIndex = 0
                    Case "DESCRIPTION"
                        fieldIndex = 1
                    Case "NAME"
                        fieldIndex = 2
                    Case "CUSTOMERID"
                        fieldIndex = 3
                    Case "ADDRESS"
                        fieldIndex = 4
                    Case "TOWN"
                        fieldIndex = 5
                    Case "POSTALCODE"
                        fieldIndex = 6
                End Select
    
                rs(fieldIndex) = xNode.nodeValue
    
    
            Else
    
                'CHECK FOR THE NODE WHICH CONTAINS THE SETS OF DATA'
                If xNode.parentNode.nodeName = "data" Then
                    'next record
                    If recordCount > 0 Then
                        'save previous record
                        rs.Update
                        fieldIndex = 0
                    End If
                    rs.AddNew
                    recordCount = recordCount + 1
                End If
    
    
            End If
    
            If xNode.hasChildNodes Then
               'recurive call for the next node 
              LoadNodesIntoRs xNode.childNodes, rs, recordCount
            End If
    
        Next xNode
    
    End Sub
    

    【讨论】:

    • VBA 字符串变量绝对不限于 255 个字符。你从哪里得到这个疯狂的想法?
    • 确实很疯狂,我删除了它。
    猜你喜欢
    • 2021-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多