はじめに
WinMergeでMicrosoft Office、PDF、その他のドキュメントファイルを比較するためのプラグイン「markitdown.sct」を作成しました。
WinMergeでバイナリファイルを比較するためには、テキストファイルに変換する手順が必要です。
Officeドキュメントのテキストファイル変換で、従来のxdocdiff WinMerge Pluginの代わりに、MicrosoftのMarkItDownを使用してOfficeドキュメントをMarkdown形式に変換します。
なぜ作ったのか?
Officeドキュメントの変更管理、どうしていますか?
昨今のOfficeドキュメントは、単なるドキュメントにとどまらず、システムの自動生成ソースとして利用されることも増えています。そのため、想定外の変更がシステムに予期せぬ影響を与えることがあります。
変更箇所の把握方法として、修正履歴を記載したり、吹き出しや文字色・セル色で目立たせたりする方法もありますが、これらは作成者の自己申告に依存しています。修正前のドキュメントを用意して全量を目視で突き合わせるのも現実的ではありません。
そこで有効なのが、xdocdiff WinMerge Pluginを使った機械的な比較です。Officeファイルの全量比較といえばこのツール。これまで何度もお世話になってきました。
導入時のもやもや
ただ、xdocdiff WinMerge Pluginをセットアップをするたびに、いくつかのもやもやがありました。
| 課題 | 内容 |
|---|---|
| バージョン管理 | 複数フォーク版が存在、更新の自動化が困難 |
| 配布形式 | 個人サイトからの実行ファイルダウンロードが必要(参考リンク参照) |
| 企業環境 | 個人開発ツールの導入にはセキュリティ審査が必要な場合も |
| セットアップ | 実行ファイルの配置、パス設定など独自の手順が多い |
MarkItDownとの出会い
そんなとき、生成AIで大活躍しているMicrosoft公式のMarkItDownを発見しました。
MarkItDownは、Microsoftが開発・公開しているドキュメント変換ツールです。
- GitHub 8万スター超の人気プロジェクト
- Office、PDF、画像、音声など幅広い形式をMarkdownに変換
-
pip install markitdown[all]で簡単インストール - Microsoftによる継続的なメンテナンス(Office形式の仕様変更にも追従が期待できる)
これなら企業環境でも導入しやすい!というわけで、xdocdiffの設計思想を引き継ぎつつ、MarkItDownベースのプラグインを作成しました。
生成AI時代のユースケース
MarkItDownは、生成AIとの連携で真価を発揮します:
| ユースケース | 説明 |
|---|---|
| RAG(検索拡張生成) | 社内ドキュメントをMarkdown化してベクトルDBに投入し、AIが検索・回答 |
| MCP連携 | MCPサーバーとして動作し、ローカルファイルを直接参照 |
| コンテキスト提供 | ChatGPTやCopilotにOffice文書の内容を正確に伝える |
| ドキュメント要約 | 大量の設計書やマニュアルをAIに読み込ませて要約・分析 |
具体例: 「この設計書の変更点を要約して」とAIに依頼するとき、MarkItDownで変換したMarkdownを渡せば、表構造や見出し階層を維持したまま正確に伝わります。
本プラグインは、このMarkItDownをWinMergeの差分比較に活用したものです。
xdoc2txtとの比較
xdocdiff系プラグインは内部でhishida様のxdoc2txtを使用しています。本プラグインはこれをMarkItDownに置き換えたものです。両者の違いを比較します。
比較結果の見た目
以下のようなExcelファイルを比較してみます。
比較対象のExcelファイル(左: 修正前、右: 修正後)
今回作成したMarkItDownプラグイン(Markdown形式)
大量のNaNが出力されていますがMarkdown形式になっています。Excel方眼紙の場合はさらに大量のNaNが出力されます。
Excelの表構造も無視されており、人間が見るには厳しいと言わざるをえません。
百戦錬磨のxdoc2txtプラグイン(テキスト形式)
すっきりしていて見やすいですね。設計書であればどこに何が書いてあるかを把握しているので、人間が見るにはこれで十分です。
WinMerge同梱の公式プラグインであるCompareMS~Files.sct
WinMerge同梱の公式プラグインとして、Excel/Word/PowerPoint/Visioそれぞれ専用のプラグインが用意されていますので、こちらにも言及します。
Office COMオートメーション経由で高精度な抽出が可能ですが、対応Officeアプリのインストールが必要で、大きなファイルでは処理に時間がかかります。
この処理速度と安定性がネックで私は利用していません。

プラグインオプションも豊富で、かゆいところに手が届きそうです。
機能比較表
| 項目 | xdoc2txt | MarkItDown | CompareMS~Files.sct |
|---|---|---|---|
| 開発元 | 個人開発 | Microsoft | WinMerge公式 |
| 配布形式 | 実行ファイル | pip install | WinMerge同梱 |
| 出力形式 | プレーンテキスト | Markdown | TSV(セル単位) |
| 処理速度 | 🚀 爆速 (2秒) | 普通 (15秒) | 🐌 かなり遅い (2分45秒) |
| 人間向け | ⭕ 見やすい | ❌ NaN地獄 | ⭕ 非常に見やすい |
| AI向け | △ | ⭕ Markdown形式 | △ |
| Office対応 | ✅ | ✅ | ✅ (Visioにも対応!) |
| PDF対応 | ✅ | ✅ | ❌ |
※処理速度は15MBのExcelファイルを比較した場合の参考値(環境により異なります)
MarkItDownの処理速度について(正直な話)
MarkItDownはxdoc2txtより明らかに遅いです。 その理由は以下の通りです。
- 起動オーバーヘッド: Pythonインタプリタの起動とライブラリ読み込みに0.5〜1秒かかる
- PDF解析: 純Python製ライブラリ(pdfminer.six)を使用しているため遅い
- 処理の複雑さ: テキスト抽出だけでなく、Markdown構造への変換処理も行っている
どちらを選ぶべきか?
処理速度のネックから、CompareMS~Files.sctは除外する。
| 利用者 | 推奨 | 理由 |
|---|---|---|
| 🧑 人間 | xdoc2txt | 爆速+見やすい |
| 🤖 AI | MarkItDown | Markdown形式で構造化 |
| 🏢 企業環境 | MarkItDown | Microsoft公式ツール、pipで導入可能 |
正直なところ: xdoc2txt、MarkItDownのどちらの変換テキストも、人間が利用する場合において100点ではありません。WinMergeの差分比較だけでは完結せず、Officeドキュメントをアプリで開いて目視での確認が必要です。
であれば、普段は処理速度が🚀 爆速なxdocdiffPlugin64を使い、AIにOffice文書の変更内容を正確に伝えたいときだけmarkitdown.sctに切り替えるのがおすすめです。
それでは、MarkItDown版プラグインのセットアップ手順について説明していきます。
対応ファイル形式
対応形式
| カテゴリ | 拡張子 |
|---|---|
| Microsoft Office |
.doc, .docx, .docm, .xls, .xlsx, .xlsm, .ppt, .pptx, .pptm
|
.pdf |
|
| その他 |
.rtf, .epub, .eml
|
除外した形式(理由あり)
| 形式 | 除外理由 |
|---|---|
| CSV/JSON | プレーンテキスト比較の方が見やすい |
| HTML/XML | タグ構造が重要なので、そのまま比較すべき |
| ZIP | 中身が全展開されて逆に見づらい |
注意: OpenDocument形式(.odtなど)や一太郎(.jtd)には対応していません。
セットアップ手順(5分で完了)
前提条件
- Python 3.10以上がインストールされていること
- WinMergeがインストールされていること
ステップ1: MarkItDownのインストール
PowerShellで以下を実行:
pip install markitdown[all]
重要⚠️: [all]を忘れずに。これがないとExcel/Word/PowerPointの変換でエラーが発生します。
ステップ2: プラグインファイルの配置
markitdown.sctを以下に配置(管理者権限が必要):
C:\Program Files\WinMerge\MergePlugins\markitdown.sct
ステップ3: 動作確認
- WinMergeを起動
- メニュー: プラグイン → プラグインの設定
- リストに
markitdownが表示されていればOK - markitdownのチェックボックスをオンにしてプラグインを有効にする。(amb_xdocdiffpluginを利用している場合はチェックボックスをオフにすることを推奨)
- ファイルフィルターは自動で設定されます。プラグイン引数は空欄で
ソースコード
markitdown.sct(クリックで展開)
<scriptlet>
<implements type="Automation" id="dispatcher">
<property name="PluginEvent">
<get/>
</property>
<property name="PluginDescription">
<get/>
</property>
<property name="PluginFileFilters">
<get/>
</property>
<property name="PluginIsAutomatic">
<get/>
</property>
<method name="UnpackFile"/>
<method name="PackFile"/>
<method name="ShowSettingsDialog"/>
</implements>
<script language="VBS">
'/////////////////////////////////////////////////////////////////////////////
' This is a plugin for WinMerge.
' Copyright (C) 2025 @ishikawa-oniisan
'
' Based on xdocdiffU.sct:
' Copyright (C) 2020 stonee
'
' Original xdocdiff WinMerge Plugin:
' http://freemind.s57.xrea.com/xdocdiffPlugin/
'
' Original xdocdiffPlugin64:
' http://crus.mydns.jp/xdocdiffPlugin64/
'
' This version uses MarkItDown (https://github.com/microsoft/markitdown)
' instead of xdoc2txt.exe for file conversion.
'
' This program is free software; you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation; either version 2 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY; without even the implied warranty of
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
' GNU General Public License for more details.
'
' You should have received a copy of the GNU General Public License
' along with this program; if not, see <https://www.gnu.org/licenses/>.
'
Option Explicit
Dim fso: Set fso = CreateObject("Scripting.FileSystemObject")
Dim wsh: Set wsh = CreateObject("WScript.Shell")
Function get_PluginEvent()
get_PluginEvent = "FILE_PACK_UNPACK"
End Function
Function get_PluginDescription()
get_PluginDescription = "Display the text content of MS Word, Excel, PowerPoint and other office files as Markdown. (via MarkItDown)"
End Function
Function get_PluginFileFilters()
' MarkItDown supports: PDF, PowerPoint, Word, Excel, EPUB, Email
' Note: CSV, JSON, HTML, XML are excluded as they are better compared as plain text
' Note: ZIP is excluded as it expands all contents making comparison harder
' Note: MHT is excluded as HTML structure is lost during conversion
' Note: Legacy Japanese formats (Ichitaro, OASYS) and OpenDocument formats are NOT supported
get_PluginFileFilters = "\.pdf;\.docx;\.docm;\.doc;\.xlsx;\.xlsm;\.xls;\.pptx;\.pptm;\.ppt;\.rtf;\.epub;\.eml$"
End Function
Function get_PluginIsAutomatic()
get_PluginIsAutomatic = True
End Function
Function UnpackFile(fileSrc, fileDst, pbChanged, pSubcode)
On Error Resume Next
' Check if source file exists
If Not fso.FileExists(fileSrc) Then
UnpackFile = False
Exit Function
End If
' Create empty destination file first to avoid timing issues
' (This addresses the same issue mentioned in the original xdocdiffU.sct)
Dim objFile: Set objFile = fso.CreateTextFile(fileDst, True)
If Err.Number <> 0 Then
UnpackFile = False
Exit Function
End If
objFile.WriteLine ""
objFile.Close
Set objFile = Nothing
' Execute MarkItDown to convert file to Markdown
' Use UTF-8 encoding for output (consistent with xdocdiffU.sct's UTF-8 modification)
' MarkItDown outputs UTF-8 by default, so we redirect stdout to the destination file
Dim cmd
' Note: In VBScript/WSH, we use & instead of && for command chaining in cmd.exe
cmd = "cmd /c ""chcp 65001 >nul & markitdown """ & fileSrc & """ > """ & fileDst & """ 2>&1"""
Dim result
result = wsh.Run(cmd, 0, True)
If Err.Number <> 0 Then
UnpackFile = False
Exit Function
End If
' Check if conversion was successful by verifying the output file has content
If fso.FileExists(fileDst) Then
Dim fileSize
fileSize = fso.GetFile(fileDst).Size
If fileSize > 0 Then
pbChanged = True
pSubcode = 0
UnpackFile = True
Else
' If file is empty, conversion failed
pbChanged = False
pSubcode = 0
UnpackFile = False
End If
Else
pbChanged = False
pSubcode = 0
UnpackFile = False
End If
On Error Goto 0
End Function
Function PackFile(fileSrc, fileDst, pbChanged, pSubcode)
' Packing is not supported (read-only plugin)
PackFile = False
End Function
Function ShowSettingsDialog()
MsgBox "This plugin converts Office files to Markdown using MarkItDown." & vbCrLf & vbCrLf & _
"Supported formats:" & vbCrLf & _
"- Microsoft Office: Word, Excel, PowerPoint" & vbCrLf & _
"- PDF documents" & vbCrLf & _
"- EPUB (eBooks)" & vbCrLf & _
"- Email: .eml" & vbCrLf & _
"- RTF documents" & vbCrLf & vbCrLf & _
"Excluded: CSV, JSON, HTML, XML, ZIP, MHT" & vbCrLf & _
"(better compared as plain text or binary)" & vbCrLf & vbCrLf & _
"Requirements:" & vbCrLf & _
"- markitdown must be installed and in PATH" & vbCrLf & _
" (Install with: pip install markitdown[all])", _
vbInformation, "MarkItDown Plugin"
End Function
</script>
</scriptlet>
実装の詳細
技術的な詳細(クリックで展開)
既存プラグインとの比較
元のxdocdiffPlugin64のソースコード(C++)を掘り起こして確認したところ、以下の実装になっていました:
// xdoc2txtの呼び出し
tsxdoc2txtParam = L"xdoc2txt -f " + tsxdoc2txtParam;
::CreateProcess(NULL, xdoc2txtParam, NULL, NULL, NULL,
CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS,
NULL, NULL, &si, &pi);
一方、xdocdiffU.sctでは以下のように実装されていました(VBScriptだとシンプル!):
cmd = "cmd /c xdoc2txt.exe -i -8 """ & fileSrc & """ > """ & fileDst & """"
本プラグイン(markitdown.sct)では、xdocdiffU.sctの方針(標準出力リダイレクト、UTF-8明示)を踏襲しています:
cmd = "cmd /c ""chcp 65001 >nul & markitdown """ & fileSrc & """ > """ & fileDst & """ 2>&1"""
ポイント:
-
chcp 65001: UTF-8コードページに切り替え(文字化け対策) -
2>&1: 標準エラーもキャッチ(エラーメッセージを見逃さない) -
引用符のエスケープ地獄(VBScriptあるある)
ファイル生成タイミングの制御
WinMergeのプラグインAPIでは、変換処理中に出力ファイルの存在をチェックする場合があります。特にネットワークドライブ上のファイルを処理する際、変換完了前にチェックが実行されるとエラーになる可能性があります。
対策: 変換処理の前に空ファイルを作成
' Create empty destination file first to avoid timing issues
Dim objFile: Set objFile = fso.CreateTextFile(fileDst, True)
objFile.WriteLine ""
objFile.Close
Set objFile = Nothing
この実装により、WinMerge側の存在チェックが成功し、安定した動作が実現できます。
この手法は、stonee様のxdocdiffU.sctの記事で紹介されている不具合対処方法を参考にしています。
エラー処理の強化(信頼性向上)
変換失敗を確実に検出するため、以下の確認処理を実装しています:
' Check if conversion was successful by verifying the output file has content
If fso.FileExists(fileDst) Then
Dim fileSize
fileSize = fso.GetFile(fileDst).Size
If fileSize > 0 Then
pbChanged = True
pSubcode = 0
UnpackFile = True
Else
' If file is empty, conversion failed
pbChanged = False
pSubcode = 0
UnpackFile = False
End If
End If
ポイント:
- 変換後のファイルが0バイトでないかを確認
- 変換失敗時に「変更なし」と誤認されるのを防止
- より確実なエラー検出により、安定した動作を実現
文字エンコーディング(地味に重要)
- 出力: UTF-8 (BOMなし) ← 標準的
- コマンドプロンプト: UTF-8 (chcp 65001) ← 文字化け防止
- MarkItDownはデフォルトでUTF-8出力 ← ナイス設計
トラブルシューティング
| 症状 | 原因 | 解決方法 |
|---|---|---|
| MarkItDownが見つからない | PATHが通っていない |
Get-Command markitdownで確認 |
| FileConversionException |
[all]なしでインストール |
pip install markitdown[all]で再インストール |
| 変換エラー | 原因不明 | コマンドラインで直接テスト: markitdown "test.docx"
|
| 日本語が文字化け(ほとんど起きないはず) | WinMergeの設定 | オプション → コードページ → UTF-8 |
最頻出エラー: FileConversionException
以下のエラーが出たら、[all]付きで再インストール:
pip uninstall markitdown
pip install markitdown[all]
さいごに
本プラグインは、stonee様のxdocdiffU.sctのコードを参考に(というかほぼ流用して)作成しました。xdocdiff WinMerge Pluginという偉大な先人のツールがなければ、このアイデアは生まれませんでした。開発者の皆様に感謝します。
毎日、大量のレビュー依頼を捌かなければならないが、量との戦いで質を下げたくない。
そういう人に読んでいただきたいと思って執筆しました。
Excel設計書やWordドキュメントの変更箇所を瞬時に全量把握する手段があるということが知られる機会になればと思います。
Happy Diffing! 🎉
ライセンス・参考リンク
ライセンス: GPL v2
参考リンク:
- xdocdiffU.sct (stonee様)
- MarkItDown (Microsoft)
- xdocdiffPlugin64 (来栖光明様)
- xdoc2txt (hishida様)
- xdocdiff WinMerge Plugin (S.Kohno様)
- WinMerge
作成日: 2025-12-03
バージョン: 1.0





