【问题标题】:Parsing DOM using XML (VBA)使用 XML (VBA) 解析 DOM
【发布时间】:2016-12-23 06:42:48
【问题描述】:

我正在尝试编写筛选此 DOM 结构的代码:

<html>
 <head>
  <body>
   <table id="the-table" border="1">
    <thead>
    <tbody>
     <tr> </tr>
     <tr>
      <td class="x-grid3-hd-inner" bgcolor="#8dd5e7" colspan="7">
     </tr>
     <tr>
      <td class="x-grid3-hd-inner" bgcolor="#8dd5e7" colspan="7">
     </tr>
     <tr>
     <tr>
      <td class="oneline">2</td>
      <td class="oneline">ENB</td>
      <td class="oneline">2</td>
      <td class="oneline">CELL_99</td>
      <td class="oneline">255.255.255.0</td>
      <td class="oneline">My Group</td>
      <td class="oneline">*</td>
     </tr>
     <tr>
     <tr>
     <tr>
     ...
     <tr>
     <tr>
   </tbody>
  </table>
 </body>
</html>

我正在尝试为表的所有 tr 元素提取每个 td 元素处的文本。我在上面扩展了一个例子。表格的所有 td 元素都使用相同的 html 结构进行格式化(除了表格的标题)。这是我迄今为止使用的方法。

Sub ParseWebPage(url As String, sheet As String, searchCrit As String)
    Dim objXML As MSXML2.DOMDocument
    Set objXML = New MSXML2.DOMDocument
    Set htm = CreateObject("htmlFile")
    With CreateObject("msxml2.xmlhttp")
      .Open "GET", url, False
      .send
      xmlresp = .responseText
    End With
    objXML.loadXML (xmlresp)
    Dim objElem As MSXML2.IXMLDOMElement
    Debug.Print xmlresp

    objXML.loadXML (xmlresp)
    Set objElem = objXML.selectSingleNode("tr")
    Debug.Print "Found" & objElem.text
End Sub

问题是,每次我的 objElem 返回时都是空的。我也尝试使用 NodeList 而不是 IXMLDOMElement 但它总是返回空。

我认为问题出在字符串参数上。我尝试使用“tr”、“oneline”、“/html/body/table/tbody”,并为每个“/html/body/table/tbody/tr[x]/td[y]”创建一个循环,但是这些都没有效果。

有人可以帮我吗?

【问题讨论】:

  • 您的一般做法是正确的。我认为问题在于格式不正确的 XML(来自网络的 HTML 通常是)。我看到很多&lt;tr&gt; 标签,但几乎没有&lt;/tr&gt; 结束标签。 MSXML 需要完美的 XML,所以空的应该是 &lt;tr/&gt;。还要检查 objXMLIf objXML Is Nothing Then ... - 因为您没有捕获 XML 解析错误。如果它是 Nothing - 则解析时出错。查看本指南以了解如何正确操作A Beginner's Guide to the XML DOM
  • @LoganReed 该网站已经完全形成并且可以运行并且包含所有结束标签,这可能是发生了复制错误。我会看看这个链接,看看是否有帮助。
  • 先尝试一个非常小的格式良好的 XML 示例,然后继续扩展它,直到找到错误为止。
  • @LoganReed - 因为我试图用 XML 函数解析 HTML,所以我不是走错方向了吗? stackoverflow.com/questions/2515097/…
  • 嗯,这取决于。如果你正在编写一个一般的网络爬虫,它会遇到大部分糟糕的 HTML,那么是的——这是一个错误的方法。在那种情况下,我可能会尝试使用和操作 IE 对象(因为 HTML 解析将由浏览器完成)。如果您正在从一个网站读取 HTML 并且它的格式正确或不正确,但您可以将其修复为格式正确 - 那么 XML 解析器是您的最佳选择,因为它更容易和更快。

标签: html xml vba


【解决方案1】:
Sub test()
  Dim objList As MSXML2.IXMLDOMNodeList
  Dim objxml As New MSXML2.DOMDocument
  Dim i As Integer

  objxml.Load ("C:\test.xml") 'used load, loadXML would be correct for your use
  Set objList = objxml.SelectNodes("//tr/td")
  For i = 0 To objList.Length - 1
      Debug.Print objList.Item(i).Text
  Next i
End Sub

在下面使用了上面的代码:

<html>
 <head>
  <body>
   <table id="the-table" border="1">
    <thead>
     <tbody>
      <tr>
      <td class="oneline">2</td>
      <td class="oneline">ENB</td>
      <td class="oneline">2</td>
      <td class="oneline">CELL_99</td>
      <td class="oneline">255.255.255.0</td>
      <td class="oneline">My Group</td>
      <td class="oneline">*</td>
     </tr>
   </tbody>
   </thead>
  </table>
 </body>
 </head>
</html>

已将输入文件保存为 .xml。我从中得到了想要的结果。这让我相信正在发生以下情况之一:

  1. 您之前的 xmlresp 格式不正确。你能检查一下或者导出 objxml 看看它的形成是否正确吗?
  2. 您的输入字符串对于 vba 的 msxml2 来说太大了。我曾经遇到过这种情况,其中来自 adobe 的 xfdf 数据超过了某个最大字符串长度,导致输入无法正确形成。当我在 vba 之外运行 XSL 或删除带有长字符串的字段时,它起作用了。
  3. 处理 XML 和 HTML 的方式有所不同。我对 HTML 不是很熟悉,所以不能过多地评论你的那部分代码

【讨论】:

  • 我检查了数字 2。html 中有一个废话,我的意思是这样。源代码看起来很糟糕。
【解决方案2】:

如果您尝试获取 td 元素中的所有文本(“2”、“ENB”等),请尝试以下操作:

Dim objList As MSXML2.IXMLDOMNodeList
Set objList = objXML.SelectNodes("//tr/td")
For i = 0 To objList.Length - 1
   Debug.Print objList.Item(i)
Next i

希望有效。没有时间测试,但从我拥有的类似工作代码中复制。

【讨论】:

  • 节点列表还是空的。似乎使用 selectNodes/selectSingleNode 仅适用于 xml。我现在正试图将其缩减为更小的测试用例。
【解决方案3】:
Sub ParseWebPage(url As String, sheet As String, searchCrit As String)
 Dim objXML As MSXML2.DOMDocument
 Set objXML = New MSXML2.DOMDocument
 Set htm = CreateObject("htmlFile")
 Dim tableData() As String
 Dim openPos, closePos As Integer
 Dim midPart As String

 With CreateObject("msxml2.xmlhttp")
    .Open "GET", url, False
    .send
    xmlresp = .responseText
 End With
 objXML.loadXML (xmlresp)
 tableData = Split(xmlresp, searchCrit)

 For i = 12 To UBound(tableData) - 1
    openPos = InStr(tableData(i), Chr(34) & ">")
    closePos = InStr(tableData(i), "</td>")
    midPart = mid(tableData(i), openPos + 2, closePos - openPos - 2)
    Debug.Print midPart
 Next i
End Sub

目前这是一个不错的解决方案。但是,我将继续对该主题进行更多研究。我最终根本没有使用 XML 库。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-18
    • 2012-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-19
    • 2013-01-31
    • 2013-07-18
    相关资源
    最近更新 更多