XML解析VBA excel(函数行,&MSXML2.DOMDocument)

Ber*_*nes 3 xml excel parsing vba domdocument

我需要解析数百个具有相同结构的 XML 文件,如下所示:

\n\n
<?xml version="1.0" encoding="UTF-8"?>\n  <Concepts>\n    <ConceptModel name="food">\n      <Filters>\n        <Filter type="CC"/>\n      </Filters>\n      <Queries>\n        <Query lang="EN">(cheese, bread, wine)</Query>\n        <Query lang="DE">(K\xc3\xa4se, Brot, Wein)</Query>\n        <Query lang="FR">(fromaige, pain, vin)</Query>\n      </Queries>\n    </ConceptModel>\n  </Concepts>\n
Run Code Online (Sandbox Code Playgroud)\n\n

我在互联网上阅读了几篇文章和帖子,如下所示,但我无法想出解决方案:

\n\n\n\n

到目前为止我正在做:

\n\n\n\n
<?xml version="1.0" encoding="UTF-8"?>\n  <Concepts>\n    <ConceptModel name="food">\n      <Filters>\n        <Filter type="CC"/>\n      </Filters>\n      <Queries>\n        <Query lang="EN">(cheese, bread, wine)</Query>\n        <Query lang="DE">(K\xc3\xa4se, Brot, Wein)</Query>\n        <Query lang="FR">(fromaige, pain, vin)</Query>\n      </Queries>\n    </ConceptModel>\n  </Concepts>\n
Run Code Online (Sandbox Code Playgroud)\n\n

这段代码似乎可以被VBA理解,但它不读取内容。循环不会被读取,这意味着(我猜)查询根本没有循环。事实证实了这一点Msgbox "how many queries"。但实际上有三个查询。有人可以帮我吗?

\n\n

作为第二个问题我想问一下

\n\n
Dim oXml As MSXML2.DOMDocument\nSet oXml = New MSXML2.DOMDocument\noXml.LoadXML ("C:\\folder\\folder\\name.xml")\n\nDim Queries As IXMLDOMNodeList\nDim Query As IXMLDOMNode\n\nThisWorkbook.Sheets(3).Cells(i, 1) = "before loop"\n\nSet Queries = oXml.SelectNodes("/concepts/Queries")\n\nMsgBox "how many Queries " &  Queries.Length\n\nFor Each Query In Queries\n    ThisWorkbook.Sheets(3).Cells(i, 1) = "Works"\n    ThisWorkbook.Sheets(3).Cells(i, 2) = Query.SelectNodes("Query").iTem(0).Text\n    i = i + 1\nNext\n
Run Code Online (Sandbox Code Playgroud)\n\n

会是一样的

\n\n
 Dim oXml As MSXML2.DOMDocument\n
Run Code Online (Sandbox Code Playgroud)\n\n

自从我签入工具/参考文献“Microsof XML,v6.0”以来

\n\n

我认为具有标签 \n \n 的查询可能会导致问题。我添加了以下几行:

\n\n
 Dim oXml As MSXML2.DOMDocument60\n
Run Code Online (Sandbox Code Playgroud)\n\n

结果也为 0。我期望是 3,因为概念有三个子项,即ConceptModel、FilterQueries。所以,我更加疑惑了。

\n

T.M*_*.M. 9

尽可能接近你的OP

我提请您注意几个错误或误解:

  • [1]无效的.LoadXML语法

那么 .LoadXML ("C:\folder\folder\name.xml") 和 .Load ("C:\folder\folder\name.xml") 之间有什么区别?

Load需要一个文件路径,然后将文件内容加载到 oXML 对象中。

LoadXML不需要文件参数,但其实际XML 文本内容必须是格式良好的字符串。

  • [2]XML 区分大小写,因此节点需要通过其确切的文字名称来寻址:节点不会由"query"<Query>标识,"ConceptModel"与"conceptmodel"不同。

作为第二个问题,我想问是否 Dim oXml As MSXML2.DOMDocument 与相同 Dim oXml As MSXML2.DOMDocument60因为我签入了工具/参考文献“Microsof XML,v6.0”?

不,不是。- 请注意,之前的声明将默认加载 3.0 版本。然而,绝对最好使用 6.0 版本(如今任何其他版本都已过时!)

当您使用所谓的早期绑定(引用“Microsoft XML,v6.0”)时,我将执行相同的操作,但引用的是当前版本 6.0:

Dim oXml As MSXML2.DOMDocument60        ' declare the xml doc object
Set oXml = New MSXML2.DOMDocument60     ' set an instance of it to memory
Run Code Online (Sandbox Code Playgroud)
  • [3]误解一些 XPath 表达式

XPath 表达式中的起始斜杠“/”始终引用 DocumentElement(<Concepts>此处),您可以将.DocumentElement其添加到文档对象中。起始双斜杠“//xyz”将找到任何“xyz”节点(如果存在)。

例如

    oXml.SelectNodes("//Query").Length 
Run Code Online (Sandbox Code Playgroud)

返回与以下相同的 childNodes 编号(此处:3)

    oXml.DocumentElement.SelectNodes("//Query").Length   ' or 
    oXml.SelectSingleNode("//Queries").ChildNodes.Length ' or even       
    oXml.SelectNodes("/*/*/*/Query").Length`.
Run Code Online (Sandbox Code Playgroud)

参考 XML 版本 6.0 的代码示例

当然,您必须循环遍历多个 xml 文件,该示例仅使用一个(从第 2 行开始)。

针对xml 文件格式不正确的情况,我添加了详细的错误例程,使您能够识别假定的错误位置。Load两者LoadXML都返回一个布尔值(如果加载正确则返回 True,否则返回 False)。

Sub xmlTest()

Dim ws   As Worksheet: Set ws = ThisWorkbook.Sheets(3)
Dim oXml As MSXML2.DOMDocument60
Set oXml = New MSXML2.DOMDocument60
With oXml
    .validateOnParse = True
    .setProperty "SelectionLanguage", "XPath"   ' necessary in version 3.0, possibly redundant here
    .async = False

    If Not .Load(ThisWorkbook.Path & "\xml\" & "name.xml") Then
        Dim xPE        As Object    ' Set xPE = CreateObject("MSXML2.IXMLDOMParseError")
        Dim strErrText As String
        Set xPE = .parseError
        With xPE
           strErrText = "Load error " & .ErrorCode & " xml file " & vbCrLf & _
           Replace(.URL, "file:///", "") & vbCrLf & vbCrLf & _
          xPE.reason & _
          "Source Text: " & .srcText & vbCrLf & vbCrLf & _
          "Line No.:    " & .Line & vbCrLf & _
          "Line Pos.: " & .linepos & vbCrLf & _
          "File Pos.:  " & .filepos & vbCrLf & vbCrLf
        End With
        MsgBox strErrText, vbExclamation
        Set xPE = Nothing
        Exit Sub
    End If

    ' Debug.Print "|" & oXml.XML & "|"

    Dim Queries  As IXMLDOMNodeList, Query As IXMLDOMNode
    Dim Searched As String
    Dim i&, ii&
    i = 2       ' start row
  ' start XPath  
    Searched = "ConceptModel/Queries/Query"                     ' search string
    Set Queries = oXml.DocumentElement.SelectNodes(Searched)    ' XPath
  ' 
    ws.Cells(i, 1) = IIf(Queries.Length = 0, "No items", Queries.Length & " items")
    ii = 1
    For Each Query In Queries
        ii = ii + 1
        ws.Cells(i, ii) = Query.Text
    Next

End With

End Sub
Run Code Online (Sandbox Code Playgroud)

附加提示

您可能还对如何通过 XMLDOM 列出所有子节点以及如何使用 VBA 从 XML 获取属性名称的示例感兴趣。

由于后来的评论,我添加了进一步的提示(感谢@barrowc)

“使用 MSXML v3.0 的另一个问题是默认选择语言是 XSLPatterns,而不是 XPath。有关 MSXML 版本之间的一些差异的详细信息请参见此处,讨论 两种选择语言之间的差异。”

在当前的 MSXML2 版本 6.0 中,完全支持 XPath 1.0。看来XSL模式很早就被微软实现了,基本上可以看作是W3C标准化XPath之前XPath表达式的简化子集。

MSXML2 版本 3.0 至少允许通过显式选择语言设置来集成 XPath 1.0:

oXML.setProperty "SelectionLanguage", "XPath"   ' oXML being the DOMDocument object as used in original post  
Run Code Online (Sandbox Code Playgroud)