【入門編】【上級者向け】Word文書を「XML形式」で読み込み、DOM操作で高速置換を行う実験的アプローチ – Word VBA解析バイブル

スポンサーリンク

こんにちは!Word VBAの世界へようこそ。
マクロの記録ボタンを押してコードを生成し、「なんだか動いたけれど、中身はよくわからない……」という段階を卒業すると、次に直面するのが「処理の遅さ」という壁です。

数百ページ、あるいは数万ページもある巨大なWord文書に対して `.Find.Execute` をループさせ、画面がガタガタと点滅しながら何分も待たされた経験はありませんか?

今回は、そんなWord VBAの常識を根底から覆す、「Word文書をXMLとして直接読み込み、DOM操作で瞬時に置換する実験的アプローチ」を伝授します。
ここをクリアすれば、あなたのWord VBAのスキルは間違いなくプロの領域に到達します。難しい概念も優しく噛み砕いて解説するので、一緒に「最速の自動化」の世界へ踏み出しましょう!

—

なぜ、通常の `Find / Replace` は遅いのか?

私たちが普段使っている `.Find` メソッドは、Wordの「画面(GUIエンジン)」と密接に連動しています。
Wordは、文字が置換されるたびに「画面の再描画」「レイアウトの再計算」「変更履歴の記録」といった重たい処理を裏側で実行しています。これが、数万行の文書を処理するときにフリーズしたような遅さを生む原因です。

究極の解決策:Wordファイルを「ただのテキスト(XML)」として料理する

実は、拡張子が `.docx` のファイルの実体は、ZIP形式で圧縮されたXMLファイルの束です。
つまり、以下の手順を踏めば、Wordの重たい描画エンジンを一切使わずに、メモリ上で超高速な置換が可能になります。

1. `.docx` ファイルを一時的にZIPとして解凍する
2. 本文データが格納されている `word/document.xml` を取り出す
3. DOM(Document Object Model)を使って、一瞬で文字列を書き換える
4. 再びZIPに圧縮し、拡張子を `.docx` に戻す

今回は、この一連の流れをVBA(およびVBScript/VBA連携)でスマートに実現する方法を解説します。

—

【実践】XML DOM操作による超高速置換エンジン

それでは、実際のコードを見ていきましょう。
今回は、Wordのオブジェクトモデルをバイパスし、Windows標準の `MSXML2.DOMDocument` を使ってXMLを直接書き換えるプロトタイプコードを作成しました。

以下のコードを、標準モジュールに貼り付けてみてください。

Option Explicit

‘ ==============================================================================
‘ 処理名: XML DOMを活用した超高速テキスト置換エンジン(実験的プロトタイプ)
‘ 概要: .docxファイルを裏で解凍・DOM操作・再圧縮し、数万行の置換を瞬殺する
‘ ==============================================================================
Public Sub FastXmlReplaceDemo()
Dim targetPath As String
Dim tempFolder As String
Dim xmlFilePath As String

‘ 対象のWordファイルパス(※事前にデスクトップ等に用意してください)
targetPath = ThisDocument.Path & “\TestDocument.docx”

If Dir(targetPath) = “” Then
MsgBox “対象のファイルが見つかりません: ” & targetPath, vbCritical
Exit Sub
End If

‘ 1. 作業用一時フォルダのパスを決定
tempFolder = Environ(“TEMP”) & “\WordXmlWork_” & Format(Now, “yyyymmddhhnnss”)

‘ 2. ZIP解凍してXMLを取り出す(VBScriptのShell.Applicationを使用)
Call UnzipFile(targetPath, tempFolder)

‘ 3. 本文が格納されている document.xml のパス
xmlFilePath = tempFolder & “\word\document.xml”

‘ 4. DOMを使ってXMLをメモリ上にロードし、高速置換を実行
If ExecuteXmlDomReplace(xmlFilePath, “旧キーワード”, “新キーワード”) Then
‘ 5. 成功したら再度ZIP圧縮して .docx に戻す
Call ZipFile(tempFolder, targetPath)
MsgBox “XML DOM操作による超高速置換が完了しました!”, vbInformation
Else
MsgBox “置換処理中にエラーが発生しました。”, vbCritical
End If

‘ 6. 一時フォルダのクリーンアップ
On Error Resume Next
CreateObject(“Scripting.FileSystemObject”).DeleteFolder tempFolder, True
On Error GoTo 0

End Sub

‘ — 子ルーチン: MSXML2.DOMDocument によるテキスト置換 —
Private Function ExecuteXmlDomReplace(ByVal xmlPath As String, ByVal targetText As String, ByVal replaceText As String) As Boolean
Dim xmlDoc As Object
Dim textNodes As Object
Dim node As Object

On Error GoTo ErrorHandler

‘ DOMオブジェクトの生成(バージョン独立型)
Set xmlDoc = CreateObject(“MSXML2.DOMDocument.6.0”)
xmlDoc.async = False
xmlDoc.preserveWhiteSpace = True

‘ XMLファイルの読み込み
If Not xmlDoc.load(xmlPath) Then
ExecuteXmlDomReplace = False
Exit Function
End If

‘ WordのXML構造において、テキストは主に タグの中に格納されている
‘ XPathを使用して、すべての 要素を一括取得する
‘ ※名前空間の解決が必要な場合があるため、簡易的にタグ名でループするか、全テキストノードを走査します
Set textNodes = xmlDoc.getElementsByTagName(“w:t”)

For Each node In textNodes
‘ ノード内のテキストにターゲットが含まれているか判定
If InStr(node.Text, targetText) > 0 Then
‘ 文字列の置換(VBAのReplace関数をそのまま使用)
node.Text = Replace(node.Text, targetText, replaceText)
End If
Next node

‘ 変更をXMLファイルとして上書き保存
xmlDoc.Save xmlPath
ExecuteXmlDomReplace = True
Exit Function

ErrorHandler:
ExecuteXmlDomReplace = False
End Function

‘ — 補助ルーチン: ZIP解凍 (Shell.Application) —
Private Sub UnzipFile(ByVal zipFilePath As String, ByVal destFolderPath As String)
Dim fso As Object
Dim sa As Object

Set fso = CreateObject(“Scripting.FileSystemObject”)
If Not fso.FolderExists(destFolderPath) Then
fso.CreateFolder destFolderPath
End If

Set sa = CreateObject(“Shell.Application”)
‘ ZIPファイルを解凍フォルダにコピー(Windows標準機能)
sa.NameSpace(destFolderPath).CopyHere sa.NameSpace(zipFilePath).Items
End Sub

‘ — 補助ルーチン: ZIP圧縮 (VBScript/ADODB等を利用して再圧縮) —
Private Sub ZipFile(ByVal srcFolderPath As String, ByVal destZipPath As String)
Dim fso As Object
Dim zipFile As Object
Dim sa As Object

Set fso = CreateObject(“Scripting.FileSystemObject”)

‘ 既存のzipがあれば削除して上書き準備
If fso.FileExists(destZipPath) Then fso.DeleteFile destZipPath

‘ 空のZIPファイル(ヘッダーのみ)を生成
fso.CreateTextFile(destZipPath, True).Write Chr(80) & Chr(75) & Chr(5) & Chr(6) & String(18, vbNullChar)

Set sa = CreateObject(“Shell.Application”)
‘ フォルダ内の全アイテムをZIPへ圧縮コピー
sa.NameSpace(destZipPath).CopyHere sa.NameSpace(srcFolderPath).Items

‘ 圧縮処理が完了するまで少し待機(非同期対策)
Dim startTime As Single
startTime = Timer
Do Until sa.NameSpace(destZipPath).Items.Count > 0 Or Timer – startTime > 5
DoEvents
Loop
End Sub

—

コードの重要ポイントと「知見」

このコードのどこが凄いのか、そしてなぜ初学者が陥りやすい罠を回避できているのかを解説します。

1. Wordの画面を見せない圧倒的なスピード

通常のマクロであれば `ScreenUpdating = False` にしても画面のちらつきやWord内部のレイアウトエンジンが働きますが、この手法は「ただのテキストファイル(XML)の書き換え」です。何万行ある文書であっても、一瞬(コンマ数秒)で置換が完了します。

2. Wordのテキスト構造 `` の理解

WordのXML(WordprocessingML)において、私たちが画面で見ている文字は ``(Text)というタグの中に格納されています。
DOMの `getElementsByTagName(“w:t”)` を使うことで、文書内のすべての文章のかたまりをピンポイントで抽出し、一網打尽に書き換えることができるのです。

3. 注意すべき「落とし穴」(ここが重要!)

このアプローチは非常に強力ですが、実験的アプローチと呼ぶ理由があります。それは以下のリスクが存在するからです。

  • 単語が複数の `` に分割されている場合がある

Wordで文章を編集していると、スペルチェックや書式変更のせいで、「Hello」という単語が `He` と `llo` に真っ二つに分断されていることがあります。この状態だと、単純な `.Text` の置換ではヒットしません。

  • 書式やフィールドコードの破壊リスク

表やヘッダー、フッター、あるいは特殊なフィールドコード(目次など)が絡む場合、単純なテキスト置換だけではドキュメントが破損するリスクがあります。

そのため、この手法は「書式がシンプルで、とにかく数万行の定型テキストを爆速で置換したい!」という特定の極限状況においてのみ真価を発揮します。

—

ここをクリアすれば、Word VBAの基本はバッチリ!

今回はあえて上級者向けの「XML直接操作」というディープな世界をご紹介しましたが、ここで伝えたかった本質は一つです。

「Word VBAは、画面の向こう側の操作だけではなく、ファイル構造そのものを捉えて自由自在に操ることができる」

この視点を持つだけで、あなたの自動化の引き出しは圧倒的に広がります。
最初は難しく感じるかもしれませんが、コードを一行ずつ追いかけていけば、確実に血肉になります。ぜひご自身の環境で試して、その「圧倒的なスピード」を体感してみてくださいね。

あなたの自動化ライフが、最高にエキサイティングなものになりますように!

タイトルとURLをコピーしました