Синтаксический анализ XML VBA excel (функция trip & MSXML2.DOMDocument) - PullRequest
0 голосов
/ 30 ноября 2018

Мне нужно проанализировать сотни XML-файлов, имеющих одинаковую структуру, следующим образом:

<?xml version="1.0" encoding="UTF-8"?>
  <Concepts>
    <ConceptModel name="food">
      <Filters>
        <Filter type="CC"/>
      </Filters>
      <Queries>
        <Query lang="EN">(cheese, bread, wine)</Query>
        <Query lang="DE">(Käse, Brot, Wein)</Query>
        <Query lang="FR">(fromaige, pain, vin)</Query>
      </Queries>
    </ConceptModel>
  </Concepts>

Я прочитал несколько статей и сообщений в Интернете, как показано ниже, но не смог найти решение:

Пока я делаю:

Dim oXml As MSXML2.DOMDocument
Set oXml = New MSXML2.DOMDocument
oXml.LoadXML ("C:\folder\folder\name.xml")

Dim Queries As IXMLDOMNodeList
Dim Query As IXMLDOMNode

ThisWorkbook.Sheets(3).Cells(i, 1) = "before loop"

Set Queries = oXml.SelectNodes("/concepts/Queries")

MsgBox "how many Queries " &  Queries.Length

For Each Query In Queries
    ThisWorkbook.Sheets(3).Cells(i, 1) = "Works"
    ThisWorkbook.Sheets(3).Cells(i, 2) = Query.SelectNodes("Query").iTem(0).Text
    i = i + 1
Next

Этот код, похоже, понят VBA, но он не читает содержимое.Цикл не читается, это означает (я полагаю), что запросы вообще не зациклены.Что подтверждается тем фактом, что Msgbox "how many queries" дает 0 в качестве результата.Но на самом деле есть три запроса.Может ли кто-нибудь помочь мне?

В качестве второго вопроса я хотел бы спросить, будет ли

 Dim oXml As MSXML2.DOMDocument

такой же, как

 Dim oXml As MSXML2.DOMDocument60

Поскольку я проверил инструменты/ ссылки "Microsof XML, v6.0"

Я думал, что запросы, имеющие тег, могут вызвать проблемы.и я добавил следующие строки:

Dim childs As IXMLDOMNodeList
Set childs = oXml.SelectNodes("/concepts")

MsgBox "childs " & childs.Length

, что также дает 0 в качестве результата.Я ожидал бы 3, так как у концептов есть три дочерних элемента, а именно ConceptModel, Filter и Queries .Итак, я еще более озадачен.

Спасибо.

Ответы [ 2 ]

0 голосов
/ 30 ноября 2018

Как можно ближе к вашему ОП

Обращаю ваше внимание на несколько ошибок или недоразумений:

  • [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
  • [3] неправильное понимание некоторых выражений XPath

Aначальная косая черта "/" в выражении XPath всегда относится к DocumentElement (<Concepts> здесь), вместо этого вы можете добавить .DocumentElement к объекту документа.Начальная двойная косая черта "// xyz" найдет любой узел "xyz", если он существует.

Например,

    oXml.SelectNodes("//Query").Length 

возвращает тот же номер childNodes (здесь: 3), что и

    oXml.DocumentElement.SelectNodes("//Query").Length   ' or 
    oXml.SelectSingleNode("//Queries").ChildNodes.Length ' or even       
    oXml.SelectNodes("/*/*/*/Query").Length`.

Пример кода со ссылкой на версию 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

Дополнительные подсказки

Вы также можете бытьинтересует пример, как вывести список всех дочерних узлов через XMLDOM и получить имена атрибутов из XML с помощью VBA .

Я включил еще одну подсказку из-за более позднего комментария (спасибо @barrowc)

"Еще одна проблема с использованием MSXML v3.0 заключается в том, что язык выбора по умолчаниюэто XSLPatterns вместо XPath. Подробности некоторых различий между версиями MSXML здесь , а различия между двумя языками выбора обсуждаются здесь . "

В текущей версии MSXML2 6.0 XPath 1.0 полностью поддерживается.Похоже, что XSL Patterns были реализованы Microsoft ранее, в основном это можно рассматривать как упрощенное подмножество выражений XPath до стандартизации XPath в W3C.

MSXML2 версии 3.0 позволяет интегрироватьXPath 1.0 хотя бы с помощью явного выбора языка:

oXML.setProperty "SelectionLanguage", "XPath"   ' oXML being the DOMDocument object as used in original post  
0 голосов
/ 30 ноября 2018

Это специальные символы (немецкий алфавит), означающие, что вам нужно сделать что-то вроде пакетной замены в файлах XML, поэтому открывающая строка - не это:

<?xml version="1.0" encoding="UTF-8"?>

, но это:

<?xml version="1.0" encoding="iso-8859-1" ?>

Код для проверки после:

Option Explicit
Public Sub test()
    Dim xmlDoc As Object
    Set xmlDoc = CreateObject("MSXML2.DOMDocument") 'New MSXML2.DOMDocument60
    With xmlDoc
        .validateOnParse = True
        .setProperty "SelectionLanguage", "XPath"
        .async = False
        If Not .Load("C:\Users\User\Desktop\Test.xml") Then
            Err.Raise .parseError.ErrorCode, , .parseError.reason
        End If
    End With
    Debug.Print xmlDoc.SelectNodes("//Query").Length
End Sub

Это XML-код, который я использую:

<?xml version="1.0" encoding="iso-8859-1" ?>
  <Concepts>
      <ConceptModel name="food">
    <Filters>
      <Filter type="CC"/>
    </Filters>
    <Queries>
      <Query lang="EN">(cheese, bread, wine)</Query>
      <Query lang="DE">(Käse, Brot, Wein)</Query>
      <Query lang="FR">(fromaige, pain, vin)</Query>
   </Queries>
  </ConceptModel>
</Concepts>
...