Word で好きなテンプレートの docx ファイルを自動生成する
やりたいこと
テキストファイルから読み込んだ文字列を、特定のフォーマットでdocxファイルに出力したいです。
具体的には、こんな感じで小説風の縦書き文章にしたいのです。
この記事では、docx ファイルを操作するライブラリ python-docx を使った方法を紹介していきます。
docx ファイルの中身をある程度理解できれば縦書きにする以外の応用もできると思うので、何らかの事情で docx ファイルと格闘している皆様はよかったら読んでみてください。
やり方
docx のテンプレートを用意する
wordでドキュメントを新規作成して、縦書きのテンプレートを作ってしまいます。ここでは本文は打ち込みません。
レイアウトタブ>テキストの方向>縦書き と選択すれば縦書きになります。
用紙サイズなどを指定したい場合もここで設定してしまいましょう。
template.docx など適当な名前で保存します。
テンプレートを読み込み、内容を追加する
python-docx を使います。
$ pip install python-docx
以下はテンプレートを読み込んで、本文を追加するコードの例です。
#!/usr/local/bin/python # -*- coding:utf-8 -*- from docx import Document def main(): # テンプレートを読み込む document = Document('template.docx') # 最初の段落を取得 p = document.paragraphs[0] # 文章を追加 p.add_run('吾輩は猫である。') p.add_run('名前はまだ無い。') # 新しい段落をつくる p = document.add_paragraph() # 新しい段落に文章を追加 p.add_run('こんな感じで小説風な文章を書きたい。') # 保存 document.save('out.docx') if __name__ == '__main__': main()
これを実行すると冒頭のファイルができます。
何をしているのか
docx ファイルの中身
docx ファイルは zip アーカイブになっています。unzip
で展開すると確認することができます。
試しに、縦書きのファイルの中身をみてみます。
$ unzip sample.docx -d sample_docx $ tree sample_docx sample_docx/ ├── [Content_Types].xml ├── _rels ├── customXml │ ├── _rels │ │ └── item1.xml.rels │ ├── item1.xml │ └── itemProps1.xml ├── docProps │ ├── app.xml │ └── core.xml └── word ├── _rels │ └── document.xml.rels ├── document.xml ├── fontTable.xml ├── settings.xml ├── styles.xml ├── theme │ └── theme1.xml └── webSettings.xml
本文ファイルは sample_docx/document/words.xml です。
中身は以下のようになっています。
<?xml version="2.0" encoding="UTF-8" standalone="yes"?> <w:document xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:cx2="http://schemas.microsoft.com/office/drawing/2015/10/21/chartex" xmlns:cx3="http://schemas.microsoft.com/office/drawing/2016/5/9/chartex" xmlns:cx4="http://schemas.microsoft.com/office/drawing/2016/5/10/chartex" xmlns:cx5="http://schemas.microsoft.com/office/drawing/2016/5/11/chartex" xmlns:cx6="http://schemas.microsoft.com/office/drawing/2016/5/12/chartex" xmlns:cx7="http://schemas.microsoft.com/office/drawing/2016/5/13/chartex" xmlns:cx8="http://schemas.microsoft.com/office/drawing/2016/5/14/chartex" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:aink="http://schemas.microsoft.com/office/drawing/2016/ink" xmlns:am3d="http://schemas.microsoft.com/office/drawing/2017/model3d" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 w16se w16cid wp14"> <w:body> <w:p w:rsidR="0033710F" w:rsidRPr="0011658F" w:rsidRDefault="0033710F"> <w:pPr> <w:rPr> <w:rFonts w:ascii="Hiragino Mincho Pro W3" w:eastAsia="Hiragino Mincho Pro W3" w:hAnsi="Hiragino Mincho Pro W3"/> <w:sz w:val="36"/> <w:szCs w:val="36"/> </w:rPr> </w:pPr> <w:r w:rsidRPr="0011658F"> <w:rPr> <w:rFonts w:ascii="Hiragino Mincho Pro W3" w:eastAsia="Hiragino Mincho Pro W3" w:hAnsi="Hiragino Mincho Pro W3" w:hint="eastAsia"/> <w:sz w:val="36"/> <w:szCs w:val="36"/> </w:rPr> <w:t>吾輩は猫である。</w:t> </w:r> <w:r w:rsidR="00BD0058"> <w:rPr> <w:rFonts w:ascii="Hiragino Mincho Pro W3" w:eastAsia="Hiragino Mincho Pro W3" w:hAnsi="Hiragino Mincho Pro W3" w:hint="eastAsia"/> <w:sz w:val="36"/> <w:szCs w:val="36"/> </w:rPr> <w:t>名前はまだ無い。</w:t> </w:r> <w:bookmarkStart w:id="0" w:name="_GoBack"/> <w:bookmarkEnd w:id="0"/> </w:p> <w:p w:rsidR="004919A3" w:rsidRPr="0011658F" w:rsidRDefault="004919A3"> <w:pPr> <w:rPr> <w:rFonts w:ascii="Hiragino Mincho Pro W3" w:eastAsia="Hiragino Mincho Pro W3" w:hAnsi="Hiragino Mincho Pro W3"/> <w:sz w:val="36"/> <w:szCs w:val="36"/> </w:rPr> </w:pPr> <w:r w:rsidRPr="0011658F"> <w:rPr> <w:rFonts w:ascii="Hiragino Mincho Pro W3" w:eastAsia="Hiragino Mincho Pro W3" w:hAnsi="Hiragino Mincho Pro W3" w:hint="eastAsia"/> <w:sz w:val="36"/> <w:szCs w:val="36"/> </w:rPr> <w:t>こんな感じで小説風な文章を書きたい。</w:t> </w:r> </w:p> <w:sectPr w:rsidR="004919A3" w:rsidRPr="0011658F" w:rsidSect="004919A3"> <w:pgSz w:w="16840" w:h="11900" w:orient="landscape"/> <w:pgMar w:top="1701" w:right="1701" w:bottom="1701" w:left="1985" w:header="851" w:footer="992" w:gutter="0"/> <w:cols w:space="425"/> <w:textDirection w:val="tbRl"/> <w:docGrid w:type="lines" w:linePitch="400"/> </w:sectPr> </w:body> </w:document>
色々書いてありますが、おおまかには以下の構造で書かれています。
本文(body)
ユーザが編集できる本文領域のデータです。この下に段落が配置されます。
段落(paragraph)
文章の塊はparagraph
要素(p
)で表されます。word 内で改行すると次の段落になります。 段落ごとのプロパティはpPr
要素でまとめられています。pPr
にはフォントの設定などが書かれています。
ラン(run)
段落より下位の要素です。今回の例では、「吾輩は猫である。」と「名前はまだ無い。」は同じ段落に属していますが別のランになっています。また、太字にしたり色をつけた文字などはその部分だけ別のランになります。
ランのプロパティはrPr
要素にまとめられていますrPr
にフォントの指定などがない場合は上位の段落のpPr
に書かれている内容が引き継がれます。
テキスト(text)
テキスト要素はランの下に配置されます。word で開いたときに実際に表示される文字列がここにはいります。
セクションプロパティ(sectPr)
ドキュメント全体の設定が書かれています。書字方向(縦書きか横書きかの設定)はここで指定されます。セクションプロパティの位置はbody
の直下なこともあれば段落の下にあることもあるのですが、詳しくは以下を参照してください。
python-docxでは何ができるのか
詳細は公式のドキュメントをみてもらいたいのですが、現在 python-docx の最新バージョン0.8.10では、
- 段落の追加
- ランの追加
- 図の追加
- 表の追加
がサポートされています。また、太字にする、イタリック体にする、などのプロパティは簡単に変更できるようになっています。
一方で、細かいプロパティはサポートされていないこともあります。
例えば、縦書きをするためには sectPr
要素の textDirection
要素を書き換える必要があるのですが、これは今はサポートされていません。また、ランプロパティの中には漢字にルビを振るときの設定等もあるのですが、そのあたりも現時点ではサポートされていません。
まとめ
簡単なのは、一旦手動で所望のフォーマットの docx ファイルを作成してみて、それを xml の状態で眺めてみることです。
python-docx のドキュメントと見比べて、サポートされている機能であれば python-docx で書けばよいです。縦書き設定のようなサポートされていない機能は、今回のようにテンプレートをつくってそれを読み込むことである程度対応できます。
テンプレートで対応しづらい機能(ルビをふるとか)は xml をゴリゴリ書いてどうにかする方法もあるのですが、、それはまたの機会に。