VBAを学習する過程でファイルのパスを読み込むときによく見かけるDir関数について、見慣れずどうも調べたらVBA特有らしい表記があったので、それに関する備忘録
調べたら、VBAのこのDir関数は「内部で検索状態を保持する特殊な関数」らしい。
どういうことかというと、少し前に定義している
fileName = Dir(folderPath & "*.xml")
というのは実は続いていて (ループ処理において)「直前に開始した検索の次のファイルを取得する」 ということが起きているらしい
Dir("*.xml") ←検索開始
Dir() ←次
Dir() ←次
Dir() ←次
fileName = Dir()(※VBAにおけるDirの引数なし)は再代入ではなく、
「さっきの(検索の)続きをください」 らしい
Dir()は、fileName = Dir("C:\Other\*.txt")のように 引数ありの状態で再代入 すると、(検索の)状態がリセット(というか次の検索対象に移る)らしい
そのため、次のようなコードは基本書かない
fileName = Dir(folderPath & "\" & "*.xml")
Do While fileName <> ""
'ここで別のDirを実行
txt = Dir(folderPath & "\" & "*.txt") '←検索状態が上書きされる
fileName = Dir() 'XMLの続きではなくTXTの続きになる
Loop
キモいなVBA・・・
例えばこういうやつ
Sub SameAttributeSubTagComparison()
Dim folderPath As String
Dim fileName As String
Dim xml As Object
'対象フォルダのパスをシート1のA1セルに書いた場合、それをfolderPathに格納
folderPath = Trim(ThisWorkbook.Worksheets(1).Range("A1").Text) & "\"
'MSXML 6.0 の DOMDocument オブジェクトを作成
'これをすることでxmlが読み込めるようになる
Set xml = CreateObject("MSXML2.DOMDocument.6.0")
xml.async = False
fileName = Dir(folderPath & "*.xml")
Stop
Debug.Print fileName
Do While fileName <> ""
If xml.Load(folderPath & fileName) Then
'SameAttributeSearchXmlは下に定義するSubプロシージャで xml、fileNameはその引数
'引数のxml、fileNameは上で既に定義済み
SameAttributeSearchXml xml, fileName
End If
fileName = Dir()
Loop
End Sub
'=========================================
' 以下、SameAttributeSearchXmlの定義、要素、その要素が含む属性、その子要素を見て
'属性は同じだが、子要素名が異なる場合にイミディエイトウィンドウに出力
'=========================================
Sub SameAttributeSearchXml(xml As Object, fileName As String)
Dim nodeList As Object
Dim Ele1 As Object
Dim Ele2 As Object
Dim Attr1 As String
Dim Attr2 As String
Dim SubEle1 As String
Dim SubEle2 As String
'A2セルに検索対象の要素名を記載
Set nodeList = xml.SelectNodes("//" & ThisWorkbook.Worksheets(1).Range("A2").Text)
For Each Ele1 In nodeList
'A3セルに検索対象の要素の適当な属性を記載
Attr1 = Ele1.Attributes.getNamedItem(ThisWorkbook.Worksheets(1).Range("A3").Text).Text
'A4セルに検索対象の要素の子要素を記載
SubEle1 = Ele1.SelectSingleNode(ThisWorkbook.Worksheets(1).Range("A4").Text).Text
For Each Ele2 In nodeList
If Ele1 Is Ele2 Then GoTo ContinueLoop
Attr2 = Ele2.Attributes.getNamedItem(ThisWorkbook.Worksheets(1).Range("A3").Text).Text
SubEle2 = Ele2.SelectSingleNode(ThisWorkbook.Worksheets(1).Range("A4").Text).Text
If Attr1 = Attr2 And SubEle1 <> SubEle2 Then
Debug.Print fileName & vbTab & _
"CheckedAttr" & vbTab & _
Ele1.Attributes.getNamedItem(ThisWorkbook.Worksheets(1).Range("A3").Text).Text & vbTab & _
"CheckedEle" & vbTab & _
SubEle2
Exit For
End If
ContinueLoop:
Next
Next
End Sub