【问题标题】:MSXML2.DOMDocument60 - Reading XML in VBA with NamespaceMSXML2.DOMDocument60 - 使用命名空间在 VBA 中读取 XML
【发布时间】:2021-06-11 19:15:03
【问题描述】:

我是 Access 和 MSXML2.DOMDocument60 编程的新手,所以如果有任何不正确之处,请接受我的歉意。我正在尝试解析 xml,但在使用 MSXML2.DOMDocument 加载它时遇到问题。 XML的结构如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE raml SYSTEM 'raml20.dtd'>
<raml version="2.0" xmlns="raml20.xsd">
  <cmData type="actual">
    <header>
      <log dateTime="2021-03-11T13:00:47.000Z" action="created" appInfo="ActualExporter">InternalValues are used</log>
    </header>
    <managedObject class="RETU_R" version="EQMR20A_2003_002" distName="PLMN-PLMN/MRBTS-503327/EQM_R-1/APEQM_R-1/ALD_R-1/RETU_R-1" id="136127888">
      <p name="angle">20</p>
      <list name="antBandList">
        <item>
          <p name="antBeamwidth">61</p>
          <p name="antFreqBand">1</p>
          <p name="antOperGain">185</p>
        </item>
        <item>
          <p name="antBeamwidth">60</p>
          <p name="antFreqBand">2</p>
          <p name="antOperGain">185</p>
        </item>
        <item>
          <p name="antBeamwidth">61</p>
          <p name="antFreqBand">3</p>
          <p name="antOperGain">184</p>
        </item>
      </list>
      <p name="antBearing">2800</p>
      <p name="antModel">80010825-2.1_L</p>
      <p name="antSerial">DEG3535443</p>
      <list name="antlDNList">
        <p>external</p>
      </list>
      <p name="baseStationID">45118</p>
      <p name="configDN">MRBTS-503327/EQM-1/APEQM-1/ALD-9/RETU-1</p>
      <p name="installDate">240814</p>
      <p name="installerID">CRCTL</p>
      <p name="maxAngle">60</p>
      <p name="mechanicalAngle">0</p>
      <p name="minAngle">0</p>
      <p name="operationalState">1</p>
      <p name="sectorID">3U21</p>
      <p name="subunitNumber">1</p>
    </managedObject>
    
  </cmData>
</raml>

我了解我的代码有可能导致所有问题的命名空间。我在我的 vba 中创建了错误解码消息,我收到以下错误:

“无法加载文档:C:\Audit_DB\Input Files\Test1.xml
加载时的错误是:使用了元素“raml”,但未在 DTD/Schema 中声明。”

有人可以建议我如何在此处跳过名称空间以及 vba 代码是否有任何问题。我创建的代码如下:

Sub XMLRead()

Dim path As String
Dim firstNameField As MSXML2.IXMLDOMNodeList
Dim lists As MSXML2.IXMLDOMNodeList
Dim raml As MSXML2.IXMLDOMElement

Dim i As Integer
Dim objXML As MSXML2.DOMDocument60
Set objXML = New MSXML2.DOMDocument60
path = "C:\Audit_DB\Input Files\Test1.xml"

objXML.SetProperty "ProhibitDTD", False

With objXML
    .async = False
    .Load path
    .SetProperty "SelectionLanguage", "XPath"
    .SetProperty "ProhibitDTD", False
    .SetProperty "SelectionNamespaces", "xmlns:raml='raml20.xsd'"
    Set nodeList = .selectNodes("//managedObject")
End With


If objXML.Load(path) Then
    Debug.Print "Success"
Else
    Debug.Print "Could not load the document: " & path
    If objXML.parseError.errorCode <> 0 Then Debug.Print "Error when loading was: " + objXML.parseError.reason
End If
    
Set xobjdetails = objXML.childNodes(0)
Set xObject = objXML.firstChild
    

Debug.Print objXML.selectNodes("//managedObject").length

End Sub

【问题讨论】:

    标签: xml vba ms-access xml-parsing domdocument


    【解决方案1】:

    XML 解析器正在尝试遵守文档类型声明:

    <!DOCTYPE raml SYSTEM 'raml20.dtd'>
    

    您可以提供raml20.dtd 文件,以便 XML 解析器在加载 XML 时找到它,或者您可以在 DOMDocument 中禁用自动验证和外部引用(例如 DTD)的解析(参见 @ 987654321@):

    With objXML
        ' ...
        .resolveExternals = False
        .validateOnParse = False
        ' ...
        .load "filepath"
    End With
    

    必须禁用这两个设置,否则加载将不会成功。确保在尝试加载文件之前设置它们


    话虽如此,//managedObject 不会找到任何东西,因为该节点位于 raml20.xsd 命名空间中,就像您文档中的所有其他元素一样。

    您已经将该命名空间绑定到前缀raml(使用.SetProperty "SelectionNamespaces", "xmlns:raml='raml20.xsd'"),但您也需要使用前缀:

    Debug.Print objXML.selectNodes("//raml:managedObject").length
    

    最后,您的 VBA 代码需要进行一些清理。您设置了两次ProhibitDTD,也多次调用了.load

    【讨论】:

    • 谢谢伙计,这就像一个魅力 - 我复制了它,因为我在代码中尝试了一些东西,但我相信这不是真正的原因。感谢您很好地解释了如何使用命名空间前缀选择节点。
    • @Muhammad 你可以选择任何你喜欢的前缀,顺便说一句。如果您不想一直写raml,请选择r
    • @Muhammad 可能有一个 XPath 表达式可以帮助您一次性获得正确的节点,可能类似于//raml:managedObject[@distname='something']//raml:p[@name='something'],但我们不要在这里将 cmets 设为 XPath 101。有 XPath 教程在那里,浏览其中的一些不会有什么坏处。
    • 谢谢伙计,我已经设法通过使用 for 循环的所有子节点。我只是在想是否有办法直接访问参数,但在我的水平上有点混乱。代码变得稍微大了一点,但它可以完美地读取所有节点/子节点。现在我需要找出在循环时更新访问表的最佳方法。非常感谢您的帮助
    • @UnhandledException 否。命名空间前缀只是命名空间 URI 的快捷方式。 XML 可以选择它想要的任何前缀,处理 XML 的代码可以选择它想要的任何前缀。唯一相关的是两者最终都引用了相同的命名空间 URI。 (仔细想想,如果因为输入文件突然被格式化为&lt;ns0:raml version="2.0" xmlns:ns0="raml20.xsd"&gt;,就不得不重写处理代码,那将是无稽之谈。)
    【解决方案2】:
    With objXML
        ...
        .validateOnParse = False
        ...
    End With
    

    【讨论】:

    • 谢谢兄弟,它加载得很好。欢呼
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多