docx2md.py 技術ドキュメント
プログラムの動作
docx2md.py は、Microsoft Word (.docx) ファイルの内容を抽出し、Markdown形式に変換するためのPythonスクリプトです。このプログラムは、Wordドキュメントが持つ複雑な要素、特に数式、画像、および多様なテキスト書式をMarkdownの記法で再現することを目的としています。
主な機能
テキストと書式の変換: Wordドキュメント内のプレーンテキストに加え、太字、斜体、上付き文字、下付き文字などの書式を対応するMarkdown記法(例:
**太字**,*斜体*,^上付き^,~下付き~)に変換します。数式の変換: Wordのネイティブ数式(Office Math Markup Language, OMML)を解析し、LaTeX形式に変換します。これにより、インライン数式は
$formula$、ディスプレイ(ブロック)数式は$$\nformula\n$$の形式で出力され、MathJaxやPandocなどのレンダリングツールで表示可能になります。画像の抽出とリンク: Wordドキュメントに埋め込まれた画像を抽出し、指定されたディレクトリに保存します。出力されるMarkdownファイルには、これらの画像への相対パスを示すMarkdown画像リンク(例:
)が挿入されます。構造化された要素の変換:
見出し: Wordの見出しスタイル(「見出し 1」~「見出し 4」など)を、Markdownのハッシュ記号(
#~####)による見出しに変換します。リスト: 番号付きリストと箇条書きリストを、Markdownのリスト記法に変換します。ネストされたリストにも対応しています。
テーブル: Wordのテーブルを、Markdownのテーブル構文に変換します。セル内のテキスト書式や数式も適切に処理されます。
解決する課題
本プログラムは、Wordドキュメントから情報を抽出し、以下のような用途で再利用可能にするための課題を解決します。
ドキュメントのポータビリティ向上: Wordに依存しないテキストベースの形式に変換することで、ドキュメントの共有や表示が容易になります。
ウェブコンテンツへの変換: Markdownは多くのウェブサイトやブログプラットフォームでサポートされており、本ツールを用いることでWordから直接ウェブコンテンツを生成する手助けとなります。
バージョン管理と共同編集: テキストベースのMarkdownは、Gitなどのバージョン管理システムと相性が良く、共同編集や変更履歴の追跡が容易になります。
技術文書の作成: Wordで作成された技術文書に含まれる数式やコードスニペットを、より適切な形式でMarkdownに変換できます。
原理
docx2md.py は、python-docx ライブラリを使用してDOCXファイルを読み込み、その内部XML構造を解析することで、コンテンツの変換を行います。特に、Wordの数式 (OMML) の解析には lxml ライブラリを利用しています。
Wordドキュメントの構造解析
DOCXファイルの読み込み:
docx.Document(infile_path)を使用してDOCXファイルを開きます。要素のイテレート: ドキュメントの
body要素から、Paragraph(段落)とTable(テーブル)の各ブロック要素を順に処理します。iter_inner_content()メソッドは、WordのXMLツリーの論理的な順序でこれらのブロック要素を提供します。段落内の要素: 各
Paragraph要素に対して、iter_runs_and_omath_in_orderジェネレータ関数が、段落内のRunオブジェクト(テキストの断片)とOMML数式要素を、XML内での出現順序に従って返します。これにより、テキストと数式が混在する行でも正しい順序で処理できます。
数式変換 (OMML to LaTeX)
Wordの数式は、OMML (Office Math Markup Language) と呼ばれるXML形式でDOCXファイル内に埋め込まれています。docx2md.py は、このOMMLを解析し、LaTeX形式に変換します。
OMML要素の特定: 段落内で
m:oMath(Office Math) またはm:oMathPara(Office Math Paragraph) 要素を検出します。これらの要素がWordの数式を表します。XML解析:
lxmlライブラリのetreeを使用して、検出されたOMML要素のXMLツリーを解析します。再帰的変換:
parse_omml_element関数がOMMLのXML要素を再帰的に走査し、対応するLaTeX構文に変換します。主な変換ルールは以下の通りです。テキスト要素 (
m:t):関数名(
sin,cos,logなど)は\sin,\cos,\logのようにLaTeXコマンドに変換されます。ギリシャ文字、演算子、特殊記号などは
SYMBOL_MAP辞書(例:α→\alpha,∫→\int)を使用してLaTeXコマンドにマッピングされます。
分数 (
m:f):\frac{numerator}{denominator}に変換されます。上付き/下付き (
m:sSup,m:sSub):base^{sup}またはbase_{sub}に変換されます。根号 (
m:rad):\sqrt{expression}に変換されます。括弧/デリミタ (
m:d):\leftおよび\rightコマンドを使用して、可変サイズの括弧を生成します。_latex_delimiter関数が、Wordで使用されるユニコードの括弧文字をLaTeXで安全に扱えるトークン(例:{→\{,⟨→\langle)に変換します。総和/積分 (
m:nary):\sum_{sub}^{sup} baseや\int_{sub}^{sup} baseのように変換されます。
出力形式: インライン数式は
$LaTeX_formula$で、ブロック数式は$$\nLaTeX_formula\n$$で出力されます。ブロック数式は、その前後に必ず空行を挟みます。
テキスト書式の変換
process_runs_to_markdown 関数は、段落内のRunオブジェクトの書式属性(bold, italic, font.superscript, font.subscript)をチェックし、Markdownの対応する記法に変換します。同じ書式の連続するテキストは itertools.groupby を使用してグループ化され、結合されます。
太字:
**text**斜体:
*text*太字と斜体:
***text***上付き文字:
^text^(Pandoc記法)下付き文字:
~text~(Pandoc記法)
画像抽出
画像要素の検出:
runオブジェクト内にw:drawing要素がある場合、画像が含まれていると判断します。リレーションシップIDの取得:
w:drawing要素内にあるa:blip要素のr:embed属性から、画像データへのリレーションシップIDを取得します。画像データの抽出と保存:
doc.part.related_partsを使用して、リレーションシップIDに対応する画像データ(バイナリ)を取得します。このデータを指定された--imagedirディレクトリにファイルとして保存します。Markdownリンクの生成: 保存された画像ファイルへの相対パスを含むMarkdown画像リンク
を生成します。
見出し、リスト、テーブルの処理
見出し:
handle_paragraph関数内で、段落のスタイル名(例:Heading 1)をチェックし、Markdownの#から####までの見出し記号を付加します。リスト:
Wordのリストは
w:pPr(Paragraph Properties) 内のw:numPr(Numbering Properties) を参照して識別されます。list_counters辞書を使用して、各リストのIDとレベル (numId,ilvl) ごとにカウンターを保持し、正しい番号を生成します。箇条書きリストはアスタリスク (
*) を使用し、番号付きリストは番号とピリオド (1.) を使用します。インデントはリストのレベル (
ilvl) に応じてスペース () を付加することで再現されます。
テーブル:
handle_table関数がdocx.table.Tableオブジェクトを受け取り、Markdownのテーブル構文に変換します。最初の行はヘッダーとして扱われ、その下に区切り線 (
|---|) が挿入されます。各セル内のテキストは
get_formatted_cell_text関数で書式を保持したまま処理され、改行は<br>タグに変換されます。
必要な非標準ライブラリとインストール方法
このプログラムを実行するには、以下の非標準Pythonライブラリが必要です。
python-docx: Microsoft Word (.docx) ファイルを読み書きするためのライブラリ。lxml: XMLを高速に処理するためのライブラリ。WordのOMML数式を解析するために使用されます。
これらのライブラリは、Pythonのパッケージマネージャーである pip を使用してインストールできます。コマンドプロンプトやターミナルで次のコマンドを実行してください。
pip install python-docx lxml
必要な入力ファイル
ファイル形式: Microsoft Word ドキュメント (
.docx)データ構造: プログラムは標準的なDOCXファイル形式を想定しています。
数式はWordのネイティブなOMML形式で埋め込まれている必要があります。画像として挿入された数式は変換されません。
画像はWordドキュメントに埋め込まれた形式である必要があります。リンクされた画像は正しく処理されない可能性があります。
見出し、リスト、テーブルはWordの標準機能で作成されていることを前提とします。カスタムスタイルが適用されている場合でも、スタイル名がWordの標準的な「Heading 1」や「List Paragraph」に類似していれば対応可能です。
生成される出力ファイル
Markdownファイル: コマンドライン引数
-oまたは--outputで指定されたファイル名(例:output.md)でMarkdownファイルが生成されます。このファイルには、Wordドキュメントから変換されたテキスト、書式、数式、見出し、リスト、テーブルなどがMarkdown形式で含まれます。画像ファイル: コマンドライン引数
--imagedirで指定されたディレクトリ(デフォルトはimages)に、Wordドキュメントから抽出された画像ファイルが保存されます。これらの画像ファイルは、出力されるMarkdownファイルから相対パスでリンクされます。画像ディレクトリが指定され、かつそのディレクトリ内に画像が一つも保存されなかった場合、空のディレクトリは削除されます。
コマンドラインでの使用例 (Usage)
docx2md.py はコマンドラインから実行され、引数を使用して入力ファイル、出力ファイル、およびその他のオプションを指定します。
python docx2md.py -i <入力Wordファイル名> -o <出力Markdownファイル名> [--imagedir <画像ディレクトリ名>] [--pause <一時停止フラグ>]
引数説明
-i,--input <入力Wordファイル名>(必須): 変換するWordドキュメント(.docx)のパスを指定します。例:report.docx-o,--output <出力Markdownファイル名>(必須): 生成されるMarkdownファイルのパスを指定します。例:output.md--imagedir <画像ディレクトリ名>(任意): 画像ファイルを保存するディレクトリ名を指定します。このパスは、出力Markdownファイルからの相対パスとして扱われます。指定がない場合、デフォルトでimagesというディレクトリが使用されます。例:media,attachments--pause <一時停止フラグ>(任意): プログラムの処理完了後に、ユーザーがEnterキーを押すまでプログラムを一時停止させる場合に0以外の値を指定します。デフォルトは0(一時停止なし)です。例:--pause 1
コマンドラインでの具体的な使用例
1. 基本的な変換
my_document.docx というWordファイルをMarkdown形式に変換し、my_output.md として出力します。画像がある場合、my_output.md と同じ階層に images ディレクトリが作成され、そこに保存されます。
python docx2md.py -i my_document.docx -o my_output.md
2. 画像ディレクトリを指定して変換
presentation.docx を presentation.md に変換し、抽出された画像を assets という名前のディレクトリに保存します。
python docx2md.py -i presentation.docx -o presentation.md --imagedir assets
実行結果の説明:
presentation.md ファイルが生成され、presentation.md と同じディレクトリに assets ディレクトリが作成されます。assets ディレクトリ内には、Wordファイルから抽出された画像ファイル(例: image1.png, image2.jpg など)が保存されます。presentation.md 内では、これらの画像に対して  のようなMarkdownリンクが記述されます。
3. 処理完了後に一時停止する
report.docx を report.md に変換し、変換処理が完了した後に、ユーザーが手動でEnterキーを押すまでプログラムが終了しないようにします。これは、コマンドプロンプトやターミナルがすぐに閉じてしまうのを防ぎたい場合に便利です。
python docx2md.py -i report.docx -o report.md --pause 1
実行結果の説明: 変換が正常に完了した後、コンソールに以下のメッセージが表示され、ユーザーの入力を待ちます。
変換が正常に完了しました。出力ファイル: report.md
画像は images に保存されました。
処理が完了しました。Enterキーを押すと終了します...
ユーザーがEnterキーを押すと、プログラムが終了します。