在 VBA 中是不是有循环类型、函数或方法来清理 HTML 文件中节点的嵌套 For Each 循环?
Posted
技术标签:
【中文标题】在 VBA 中是不是有循环类型、函数或方法来清理 HTML 文件中节点的嵌套 For Each 循环?【英文标题】:In VBA is there a loop type, function, or way to clean up nested For Each loops of Nodes in HTML file?在 VBA 中是否有循环类型、函数或方法来清理 HTML 文件中节点的嵌套 For Each 循环? 【发布时间】:2019-09-17 14:50:30 【问题描述】:试图找到一种方法来简化多个 For Each 循环。当我开始使用添加代码对解析的数据进行实际操作时,我意识到这需要一些工作。
我已经有一些使用 Internet Explorer 参考的工作,但我的目标是不使用任何额外的参考,因为它更快。也希望有一天能在 Mac 上使用它。我在 Excel 中编码,看看我在处理它时得到了什么。决赛实际上将在 PowerPoint 中进行。
Sub Testhtml()
'Load Document
Set objDocument = CreateObject("MSXML2.DOMDocument")
objDocument.async = False: objDocument.validateOnParse = False
objDocument.Load (ThisWorkbook.Path & "ThisFile.html")
Set ZeroNode = objDocument.DocumentElement
'Set Rows and Columns
intRow = 0
intColAttribute = 1
intColTag = 2
intColText = 3
'Loop through Nodes
For Each OneNode In ZeroNode.ChildNodes
If OneNode.HasChildNodes() Then
For Each TwoNode In OneNode.ChildNodes
If TwoNode.HasChildNodes() Then
For Each ThreeNode In TwoNode.ChildNodes
If ThreeNode.HasChildNodes() Then
For Each FourNode In ThreeNode.ChildNodes
If FourNode.HasChildNodes() Then
For Each FiveNode In FourNode.ChildNodes
If FiveNode.HasChildNodes() Then
For Each SixNode In FiveNode.ChildNodes
If SixNode.HasChildNodes() Then
For Each SevenNode In SixNode.ChildNodes
intRow = intRow + 1
If SixNode.Attributes.Length > 0 Then Worksheets("Test").Cells(intRow, intColAttribute) = SixNode.Attributes(0).Text
Worksheets("Test").Cells(intRow, intColTag) = SevenNode.BaseName
Worksheets("Test").Cells(intRow, intColText) = SevenNode.Text
Next SevenNode
Else 'SixNode.HasChildNodes()
intRow = intRow + 1
If FiveNode.Attributes.Length > 0 Then Worksheets("Test").Cells(intRow, intColAttribute) = FiveNode.Attributes(0).Text
Worksheets("Test").Cells(intRow, intColTag) = SixNode.BaseName
Worksheets("Test").Cells(intRow, intColText) = SixNode.Text
End If 'SixNode.HasChildNodes()
Next SixNode
Else 'FiveNode.HasChildNodes()
intRow = intRow + 1
If FourNode.Attributes.Length > 0 Then Worksheets("Test").Cells(intRow, intColAttribute) = FourNode.Attributes(0).Text
Worksheets("Test").Cells(intRow, intColTag) = FiveNode.BaseName
Worksheets("Test").Cells(intRow, intColText) = FiveNode.Text
End If 'FiveNode.HasChildNodes()
Next FiveNode
Else 'FourNode.HasChildNodes()
intRow = intRow + 1
If ThreeNode.Attributes.Length > 0 Then Worksheets("Test").Cells(intRow, intColAttribute) = ThreeNode.Attributes(0).Text
Worksheets("Test").Cells(intRow, intColTag) = FourNode.BaseName
Worksheets("Test").Cells(intRow, intColText) = FourNode.Text
End If 'FourNode.HasChildNodes()
Next FourNode
Else 'ThreeNode.hasChildNode()
intRow = intRow + 1
If TwoNode.Attributes.Length > 0 Then Worksheets("Test").Cells(intRow, intColAttribute) = TwoNode.Attributes(0).Text
Worksheets("Test").Cells(intRow, intColTag) = ThreeNode.BaseName
Worksheets("Test").Cells(intRow, intColText) = ThreeNode.Text
End If 'ThreeNode.hasChildNode()
Next ThreeNode
Else 'TwoNode.hasChildNode()
intRow = intRow + 1
If OneNode.Attributes.Length > 0 Then Worksheets("Test").Cells(intRow, intColAttribute) = OneNode.Attributes(0).Text
Worksheets("Test").Cells(intRow, intColTag) = TwoNode.BaseName
Worksheets("Test").Cells(intRow, intColText) = TwoNode.Text
End If 'TwoNode.hasChildNode()
Next TwoNode
Else 'OneNode.hasChildNode()
intRow = intRow + 1
Worksheets("Test").Cells(intRow, intColTag) = OneNode.BaseName
Worksheets("Test").Cells(intRow, intColText) = OneNode.Text
End If 'OneNode.hasChildNode()
Next OneNode
Set objDocument = Nothing
End Sub
这是一个 HTML 示例:
<?xml version='1.0' encoding='utf-8'?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Title</title>
<meta content="http://www.w3.org/1999/xhtml; charset=utf-8" http-equiv="Content-Type"/>
<link href="stylesheet.css" type="text/css" rel="stylesheet"/></head>
<body class="c0">
<div class="sheader" id="c_pb_21">
<span class="snumber">1</span>
<span class="stitle">Title</span>
<div class="sinfo">
InfoLine1 <br class="c1"/>
InfoLine2
</div>
</div>
<div class="sbody">
<p class="left">Intro</p>
<dl class="v">
<dt class="vnumber">1.</dt>
<dd class="vbody">
VLine1<br class="c1"/>
VLine2<br class="c1"/>
VLine3<br class="c1"/>
VLine4<p class="c6"/>
<p class="c6">VLine6<br class="c1"/>
VLine7<br class="c1"/>
VLine8<br class="c1"/>
VLine9</p>
<p class="c6">VLine11<br class="c1"/>
VLine12<br class="c1"/>
VLine13<br class="c1"/>
VLine14<br class="c1"/>
VLine15<br class="c1"/>
VLine16</p></dd>
</dl>
<dl class="v">
<dt class="vnumber">2.</dt>
<dd class="vbody">
VLine1<br class="c1"/>
VLine2<br class="c1"/>
VLine3<br class="c1"/>
VLine4<p class="c6"/>
<p class="c6">VLine6<br class="c1"/>
VLine7<br class="c1"/>
VLine8<br class="c1"/>
VLine9</p>
<p class="c6">VLine11<br class="c1"/>
VLine12<br class="c1"/>
VLine13<br class="c1"/>
VLine14<br class="c1"/>
VLine15<br class="c1"/>
VLine16</p></dd>
</dl>
<dl class="v">
<dt class="vnumber"> </dt>
<dd class="cs">
CLine1<br class="c1"/>
CLine2<br class="c1"/>
CLine3<br class="c1"/>
CLine4</dd>
</dl>
</div>
</body></html>
这是我试图从这个 HTML 中提取的内容:
snumber: 1
stitle: Title
sinfo[Line1]: InfoLine1
sinfo[Line2]: InfoLine2
left: Intro
v[1](vnumber): 1
v[1](TYPE): vbody << TYPE is from the class name
v[1](Line1): VLine1 << vbody is split at the <br class="c1"/>
v[1](Line2): VLine2
v[1](Line3): VLine3
v[1](Line4): VLine4
v[1][1](Line1): VLine6 << <p class="c6"> needs to be identified, yet <dd class="vbody"> continues
v[1][1](Line2): VLine7
v[1][1](Line3): VLine8
v[1][1](Line4): VLine9
v[1][2](Line1): VLine11
v[1][2](Line2): VLine12
...
v[2][2](Line6): VLine16
v[3](vnumber):
v[3](TYPE): cs << TYPE is from the class name
v[3](Line1): CLine1
v[3](Line2): CLine2
v[3](Line3): CLine3
v[3](Line4): CLine4
此代码有效,只是尝试清理它以便我可以更轻松地使用它。
我的最终目标是制作它,以便我可以获取多种类型的 HTML 文件并将它们“转换”为 PowerPoint。我已经以另一种方式为本示例文档完成了此操作。此代码有助于查看可以提取的内容,但实际使用信息的下一步是困难的地方。
我是编程新手,但编写了很多东西。这是我第一次在论坛发帖。
【问题讨论】:
您能否添加有关 HTML 构造的详细信息。具体来说,你对第六和第七个子节点了解多少:它们是否有特定的 ID、类、标签名称等,因为有通过这些属性检索节点的方法。也许编辑您的问题以包含一些示例 HTML。如果没有这些信息,我们很难为您提供帮助。 Protip:递归函数(和QuerySelectorAll
)。
一些子节点我在第 4 级提取信息,而在第 7 级提取信息。标签名称,类也不一致。
我对如何实现这一点的新想法持开放态度,但我也想知道是否有更好的方法来做一般的循环。即使我得到了一些关于循环以及何时在何处使用它们的培训材料。
递归遍历树而不是循环。循环做列表。
【参考方案1】:
我弄清楚了我最初想要做什么。在进行更多研究时,我发现了一个遍历文件夹的示例。我从中学到的是,潜艇可以自称。这使得清理代码成为可能。请看下面的代码:
Public intRow As Integer
Public intColAttribute As Integer
Public intColTag As Integer
Public intColText As Integer
Sub TestHTML()
'Load Document
Set objDocument = CreateObject("MSXML2.DOMDocument")
objDocument.async = False: objDocument.validateOnParse = False
objDocument.Load (ThisWorkbook.path & "\ThisFile.html")
Set ParentNode = objDocument.DocumentElement
'Set Rows and Columns
intRow = 1
intColAttribute = 1
intColTag = 2
intColText = 3
'Loop through Nodes
If Not ParentNode Is Nothing Then
TraverseNodes ParentNode
End If 'Not ParentNode
End Sub
Sub TraverseNodes(ParentNode)
For Each ChildNode In ParentNode.ChildNodes
If ChildNode.HasChildNodes() Then
TraverseNodes ChildNode
Else 'ChildNode.HasChildNodes()
intRow = intRow + 1
Debug.Print intRow
If ParentNode.Attributes.Length > 0 Then
' Here is where I can decide what to do with the Class Name
Worksheets("Test").Cells(intRow, intColAttribute) _
= ParentNode.Attributes(0).Text
End If 'ParentNode.Attributes.Length
' Here is where I can decide what to do with the Tag Name and Text
Worksheets("Test").Cells(intRow, intColTag) = ChildNode.BaseName
Worksheets("Test").Cells(intRow, intColText) = ChildNode.Text
End If 'ChildNode.HasChildNodes()
Next ChildNode
End Sub
【讨论】:
这样就简单多了。以上是关于在 VBA 中是不是有循环类型、函数或方法来清理 HTML 文件中节点的嵌套 For Each 循环?的主要内容,如果未能解决你的问题,请参考以下文章
在循环中使用多个模型时,tensorflow 或 python 是不是存在内存清理问题?