代码之家  ›  专栏  ›  技术社区  ›  Devdatta Tengshe

如何使用VBA解析XML

  •  66
  • Devdatta Tengshe  · 技术社区  · 16 年前

    我在vba工作,想分析一个字符串,例如

    <PointN xsi:type='typens:PointN' 
    xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' 
    xmlns:xs='http://www.w3.org/2001/XMLSchema'>
        <X>24.365</X>
        <Y>78.63</Y>
    </PointN>
    

    并将x&y值分成两个单独的整数变量。

    说到XML,我是个新手,因为我一直在使用vb6和vba,因为我在这个领域工作。

    我该怎么做?

    8 回复  |  直到 16 年前
        1
  •  50
  •   rjzii    7 年前

    这是一个有点复杂的问题,但看起来最直接的途径是通过msxml2.domdocument加载XML文档或XML字符串,然后通过msxml2.domdocument可以访问XML节点。

    您可以在以下站点上的msxml2.domdocument上找到更多信息:

        2
  •  68
  •   SierraOscar    9 年前

    谢谢你的指点。

    我不知道,这是否是解决问题的最佳方法,但下面是我如何让它发挥作用的。 我在我的VBA中引用了Microsoft XML v2.6 dll,然后下面的代码段给出了所需的值

    Dim objXML As MSXML2.DOMDocument
    
        Set objXML = New MSXML2.DOMDocument
    
        If Not objXML.loadXML(strXML) Then  'strXML is the string with XML'
            Err.Raise objXML.parseError.ErrorCode, , objXML.parseError.reason
        End If
    
    Dim point As IXMLDOMNode
    Set point = objXML.firstChild
    
    Debug.Print point.selectSingleNode("X").Text
    Debug.Print point.selectSingleNode("Y").Text
    
        3
  •  10
  •   SierraOscar    9 年前

    添加引用项目->引用Microsoft XML 6.0,您可以使用示例代码:

        Dim xml As String
    
        xml = "<root><person><name>Me </name> </person> <person> <name>No Name </name></person></root> "
        Dim oXml As MSXML2.DOMDocument60
        Set oXml = New MSXML2.DOMDocument60
        oXml.loadXML xml
        Dim oSeqNodes, oSeqNode As IXMLDOMNode
    
        Set oSeqNodes = oXml.selectNodes("//root/person")
        If oSeqNodes.length = 0 Then
           'show some message
        Else
            For Each oSeqNode In oSeqNodes
                 Debug.Print oSeqNode.selectSingleNode("name").Text
            Next
        End If 
    

    注意XML节点//根/人与//根/人不相同,还包括selectsinglenode(“名称”)。文本与selectsinglenode(“名称”)不相同。文本

        4
  •  8
  •   SierraOscar    9 年前

    可以使用xpath查询:

    Dim objDom As Object        '// DOMDocument
    Dim xmlStr As String, _
        xPath As String
    
    xmlStr = _
        "<PointN xsi:type='typens:PointN' " & _
        "xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' " & _
        "xmlns:xs='http://www.w3.org/2001/XMLSchema'> " & _
        "    <X>24.365</X> " & _
        "    <Y>78.63</Y> " & _
        "</PointN>"
    
    Set objDom = CreateObject("Msxml2.DOMDocument.3.0")     '// Using MSXML 3.0
    
    '/* Load XML */
    objDom.LoadXML xmlStr
    
    '/*
    ' * XPath Query
    ' */        
    
    '/* Get X */
    xPath = "/PointN/X"
    Debug.Print objDom.SelectSingleNode(xPath).text
    
    '/* Get Y */
    xPath = "/PointN/Y"
    Debug.Print objDom.SelectSingleNode(xPath).text
    
        5
  •  7
  •   SierraOscar    9 年前

    这是一个使用feeddemon opml文件的opml解析器示例:

    Sub debugPrintOPML()
    
    ' http://msdn.microsoft.com/en-us/library/ms763720(v=VS.85).aspx
    ' http://msdn.microsoft.com/en-us/library/system.xml.xmlnode.selectnodes.aspx
    ' http://msdn.microsoft.com/en-us/library/ms256086(v=VS.85).aspx ' expressions
    ' References: Microsoft XML
    
    Dim xmldoc As New DOMDocument60
    Dim oNodeList As IXMLDOMSelection
    Dim oNodeList2 As IXMLDOMSelection
    Dim curNode As IXMLDOMNode
    Dim n As Long, n2 As Long, x As Long
    
    Dim strXPathQuery As String
    Dim attrLength As Byte
    Dim FilePath As String
    
    FilePath = "rss.opml"
    
    xmldoc.Load CurrentProject.Path & "\" & FilePath
    
    strXPathQuery = "opml/body/outline"
    Set oNodeList = xmldoc.selectNodes(strXPathQuery)
    
    For n = 0 To (oNodeList.length - 1)
        Set curNode = oNodeList.Item(n)
        attrLength = curNode.Attributes.length
        If attrLength > 1 Then ' or 2 or 3
            Call processNode(curNode)
        Else
            Call processNode(curNode)
            strXPathQuery = "opml/body/outline[position() = " & n + 1 & "]/outline"
            Set oNodeList2 = xmldoc.selectNodes(strXPathQuery)
            For n2 = 0 To (oNodeList2.length - 1)
                Set curNode = oNodeList2.Item(n2)
                Call processNode(curNode)
            Next
        End If
            Debug.Print "----------------------"
    Next
    
    Set xmldoc = Nothing
    
    End Sub
    
    Sub processNode(curNode As IXMLDOMNode)
    
    Dim sAttrName As String
    Dim sAttrValue As String
    Dim attrLength As Byte
    Dim x As Long
    
    attrLength = curNode.Attributes.length
    
    For x = 0 To (attrLength - 1)
        sAttrName = curNode.Attributes.Item(x).nodeName
        sAttrValue = curNode.Attributes.Item(x).nodeValue
        Debug.Print sAttrName & " = " & sAttrValue
    Next
        Debug.Print "-----------"
    
    End Sub
    

    这一个采用多层次的文件夹树(awasu,newzcrawler):

    ...
    Call xmldocOpen4
    Call debugPrintOPML4(Null)
    ...
    
    Dim sText4 As String
    
    Sub debugPrintOPML4(strXPathQuery As Variant)
    
    Dim xmldoc4 As New DOMDocument60
    'Dim xmldoc4 As New MSXML2.DOMDocument60 ' ?
    Dim oNodeList As IXMLDOMSelection
    Dim curNode As IXMLDOMNode
    Dim n4 As Long
    
    If IsNull(strXPathQuery) Then strXPathQuery = "opml/body/outline"
    
    ' http://msdn.microsoft.com/en-us/library/ms754585(v=VS.85).aspx
    xmldoc4.async = False
    xmldoc4.loadXML sText4
    If (xmldoc4.parseError.errorCode <> 0) Then
       Dim myErr
       Set myErr = xmldoc4.parseError
       MsgBox ("You have error " & myErr.reason)
    Else
    '   MsgBox xmldoc4.xml
    End If
    
    Set oNodeList = xmldoc4.selectNodes(strXPathQuery)
    
    For n4 = 0 To (oNodeList.length - 1)
        Set curNode = oNodeList.Item(n4)
        Call processNode4(strXPathQuery, curNode, n4)
    Next
    
    Set xmldoc4 = Nothing
    
    End Sub
    
    Sub processNode4(strXPathQuery As Variant, curNode As IXMLDOMNode, n4 As Long)
    
    Dim sAttrName As String
    Dim sAttrValue As String
    Dim x As Long
    
    For x = 0 To (curNode.Attributes.length - 1)
        sAttrName = curNode.Attributes.Item(x).nodeName
        sAttrValue = curNode.Attributes.Item(x).nodeValue
        'If sAttrName = "text"
        Debug.Print strXPathQuery & " :: " & sAttrName & " = " & sAttrValue
        'End If
    Next
        Debug.Print ""
    
    If curNode.childNodes.length > 0 Then
        Call debugPrintOPML4(strXPathQuery & "[position() = " & n4 + 1 & "]/" & curNode.nodeName)
    End If
    
    End Sub
    
    Sub xmldocOpen4()
    
    Dim oFSO As New FileSystemObject ' Microsoft Scripting Runtime Reference
    Dim oFS
    Dim FilePath As String
    
    FilePath = "rss_awasu.opml"
    Set oFS = oFSO.OpenTextFile(CurrentProject.Path & "\" & FilePath)
    sText4 = oFS.ReadAll
    oFS.Close
    
    End Sub
    

    或更好:

    Sub xmldocOpen4()
    
    Dim FilePath As String
    
    FilePath = "rss.opml"
    
    ' function ConvertUTF8File(sUTF8File):
    ' http://www.vbmonster.com/Uwe/Forum.aspx/vb/24947/How-to-read-UTF-8-chars-using-VBA
    ' loading and conversion from Utf-8 to UTF
    sText8 = ConvertUTF8File(CurrentProject.Path & "\" & FilePath)
    
    End Sub
    

    但我不明白,为什么每次都要加载xmldoc4。

        6
  •  2
  •   SierraOscar    9 年前

    下面是一个子部分,用于解析包含结构钢形状数据的MicroStationTriformXML文件。

    'location of triforma structural files
    'c:\programdata\bentley\workspace\triforma\tf_imperial\data\us.xml
    
    Sub ReadTriformaImperialData()
    Dim txtFileName As String
    Dim txtFileLine As String
    Dim txtFileNumber As Long
    
    Dim Shape As String
    Shape = "w12x40"
    
    txtFileNumber = FreeFile
    txtFileName = "c:\programdata\bentley\workspace\triforma\tf_imperial\data\us.xml"
    
    Open txtFileName For Input As #txtFileNumber
    
    Do While Not EOF(txtFileNumber)
    Line Input #txtFileNumber, txtFileLine
        If InStr(1, UCase(txtFileLine), UCase(Shape)) Then
            P1 = InStr(1, UCase(txtFileLine), "D=")
            D = Val(Mid(txtFileLine, P1 + 3))
    
            P2 = InStr(1, UCase(txtFileLine), "TW=")
            TW = Val(Mid(txtFileLine, P2 + 4))
    
            P3 = InStr(1, UCase(txtFileLine), "WIDTH=")
            W = Val(Mid(txtFileLine, P3 + 7))
    
            P4 = InStr(1, UCase(txtFileLine), "TF=")
            TF = Val(Mid(txtFileLine, P4 + 4))
    
            Close txtFileNumber
            Exit Do
        End If
    Loop
    End Sub
    

    从这里,您可以使用这些值在MicroStation二维中绘制形状,或者在三维中绘制形状并将其拉伸为实体。

        7
  •  0
  •   SierraOscar    9 年前

    更新

    下面的过程给出了一个使用XML DOM对象用VBA解析XML的示例。代码基于 beginners guide of the XML DOM .

    Public Sub LoadDocument()
    Dim xDoc As MSXML.DOMDocument
    Set xDoc = New MSXML.DOMDocument
    xDoc.validateOnParse = False
    If xDoc.Load("C:\My Documents\sample.xml") Then
       ' The document loaded successfully.
       ' Now do something intersting.
       DisplayNode xDoc.childNodes, 0
    Else
       ' The document failed to load.
       ' See the previous listing for error information.
    End If
    End Sub
    
    Public Sub DisplayNode(ByRef Nodes As MSXML.IXMLDOMNodeList, _
       ByVal Indent As Integer)
    
       Dim xNode As MSXML.IXMLDOMNode
       Indent = Indent + 2
    
       For Each xNode In Nodes
          If xNode.nodeType = NODE_TEXT Then
             Debug.Print Space$(Indent) & xNode.parentNode.nodeName & _
                ":" & xNode.nodeValue
          End If
    
          If xNode.hasChildNodes Then
             DisplayNode xNode.childNodes, Indent
          End If
       Next xNode
    End Sub
    

    诺塔宾 -这个最初的答案显示了我能想象到的最简单的事情(当时我正在研究一个非常具体的问题)。 当然,使用内置于VBA XML DOM中的XML工具将是 好多了。请参阅上面的更新。

    原始响应

    我知道这是一个非常古老的帖子,但我想分享我对这个复杂问题的简单解决方案。主要我使用了基本的字符串函数来访问XML数据。

    这假定您有一些XML数据(在temp变量中)已在VBA函数中返回。有趣的是,还可以看到我如何链接到XML Web服务以检索值。图像中显示的函数也采用查找值,因为可以使用=functionname(value1,value2)从单元格中访问该Excel VBA函数,以通过Web服务将值返回到电子表格中。

    sample function

    
    openTag = "<" & tagValue & ">"
    closeTag = "< /" & tagValue & ">" 
    
    ' Locate the position of the enclosing tags startPos = InStr(1, temp, openTag) endPos = InStr(1, temp, closeTag) startTagPos = InStr(startPos, temp, ">") + 1 ' Parse xml for returned value Data = Mid(temp, startTagPos, endPos - startTagPos)
        8
  •  0
  •   TJ Wilkinson    8 年前

    当您不想启用宏时,通常在没有VBA的情况下更容易进行解析。这可以通过replace函数完成。在单元格b1和c1中输入起点和终点节点。

    Cell A1: {your XML here}
    Cell B1: <X>
    Cell C1: </X>
    Cell D1: =REPLACE(A1,1,FIND(A2,A1)+LEN(A2)-1,"")
    Cell E1: =REPLACE(A4,FIND(A3,A4),LEN(A4)-FIND(A3,A4)+1,"")
    

    结果行e1将有您的解析值:

    Cell A1: {your XML here}
    Cell B1: <X>
    Cell C1: </X>
    Cell D1: 24.365<X><Y>78.68</Y></PointN>
    Cell E1: 24.365