背景
システム開発をやっていると、Excelで書かれたドキュメントを書かせていただく機会がしばしばあります。
場合によっては、下記のようにほとんど同じ内容のファイルを大量に作らなければならないケースも、稀によくあります。
上記の2つは、買いに行く店と、買う物を除いてまったく同じ内容です。
このような場合、「八百屋買い物手順書を作成してから、文字列置換によって魚屋バージョンを作成する」という方法がありますが、Excelの貧弱な置換機能では実現できない場合もあり、泣く泣く手動による置換(いわゆる手sed)を敢行する場合も多いのではないかと思います。
そこで、Pythonからxlsxファイルを読み書きするopenpyxlと、Pythonの代表的なテンプレートエンジンjinja2を使って、Excelファイル内のテキストをテンプレートで生成することを試してみました。
pyxl.py [jinjaテンプレートを含むxlsxファイル名] [出力ファイル名] [テンプレート変数(YAML)]
このように実行することで、元のxlsxファイルに含まれる全シートの全セルを走査し、jinja2テンプレートが含まれていれば展開し、結果を別のファイルに出力します。
使い方
まず、Excelを使って下記のようなテンプレートファイルを用意します。
文法はjinja2そのものです。
テンプレートで使う変数をYAMLで記述します。
---
place: 八百屋
targets:
- name: みかん
num: 3
- name: りんご
num: 2
- name: にんじん
num: 1
---
place: 魚屋
targets:
- name: さんま
num: 2
- name: いか
num: 1
- name: たこ
num: 1
下記のように実行することで、template.xlsxとYAMLファイルから、「八百屋買い物手順書.xlsx」「魚屋買い物手順書.xlsx」が生成されます。
めでたしめでたし。
python xljj.py template.xlsx 八百屋買い物手順書.xlsx yasai.yml
python xljj.py template.xlsx 魚屋買い物手順書.xlsx sakana.yml
おまけ
openpyxlは案外多機能で、頑張ればスタイルなども変更することができます。
ただし、ドキュメントがあまり充実していないので、ドキュメントに明記されていない機能や、プライベートメソッドを呼ぶ覚悟も時には求められます。
下記は、「Excelファイルを開き、すべてのシートの"A1"セルを選択し、最初のシートに切り替えてから保存する」というこれまたよくある作業を自動的に行う関数です。
from openpyxl import load_workbook
import openpyxl.worksheet.views
def select_a1(workbook_path):
wb = load_workbook(workbook_path)
wb._active_sheet_index = 0
for ws in wb.worksheets:
ws.sheet_view.selection = (openpyxl.worksheet.views.Selection(),)
wb.save(workbook_path)