mcpField
D
docx-processing

docx-processing

github.com/pixel-process-ugドキュメント385 回インストール33 週間前に更新
リポジトリ

docx-processing について

コードによるWord文書の生成、データ入力、変換を支援するスキルで、文書自動化に適しています。python-docxとdocxtplを扱い、文書を直接作成する方法とテンプレートを使う方法を選べます。

主な機能

  1. 01python-docxによる文書作成
  2. 02docxtplによるテンプレート入力
  3. 03スタイル、表、ヘッダー、フッターの制御
  4. 04メールマージ文書の一括生成
  5. 05DOCXからPDFへの変換計画

活用シーン

  1. 01書式付きレポートの生成
  2. 02固定レイアウトのテンプレートへのデータ入力
  3. 03個別宛ての手紙の一括作成
  4. 04Word文書のPDF変換

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/pixel-process-ug/superkit-agents --skill docx-processing

インストール後、Claude Code で/docx-processingを入力して読み込まれたか確認します。

詳細

DOCX 処理

概要

Word 文書をプログラムで生成、操作し、テンプレート化します。このスキルでは、文書を直接作成するための python-docx、Jinja2 ベースのテンプレート入力に使用する docxtpl、書式設定の制御(見出し、表、画像、ヘッダー/フッター)、差し込み印刷、スタイル管理、変換方法を扱います。

Word 文書を手作業で編集せず、コードで作成、入力、変換する必要がある場合は、このスキルを適用してください。

複数フェーズのプロセス

フェーズ 1:要件
  1. ゼロから作成するか、テンプレートに入力するかを判断します
  2. 文書の構成(セクション、ヘッダー、表、画像)を特定します
  3. データソース(JSON、CSV、データベース、API)を定義します
  4. スタイル要件(フォント、色、余白)を計画します
  5. 出力形式(DOCX、PDF への変換が必要か)を決定します

停止 — 方法(ゼロから作成するか、テンプレートを使うか)を決定し、データソースを確認するまで、実装を始めないでください。

フェーズ 2:実装
  1. 文書テンプレートを設定するか、ゼロから作成します
  2. データのバインドとコンテンツの生成を実装します
  3. 書式とスタイルを適用します
  4. ヘッダー、フッター、ページ番号を追加します
  5. 画像と埋め込みオブジェクトを処理します

停止 — 文書のすべてのセクションを実装するまで、検証に進まないでください。

フェーズ 3:検証
  1. Word/LibreOffice で文書が正しく表示されることを確認します
  2. ページ間で書式の一貫性を確認します
  3. 生成した文書のデータが正確であることを検証します
  4. エッジケース(長いテキスト、欠損データ、特殊文字)でテストします
  5. 必要に応じて PDF への変換を確認します

アプローチ選択表

シナリオアプローチライブラリ理由
単発のレポート生成ゼロから作成python-docxプログラムによる完全な制御
固定レイアウトの定期レポートテンプレートdocxtplWord でレイアウトを設計し、データを入力
大量のレター生成(差し込み印刷)テンプレートdocxtpl1 つのテンプレートから多数の出力を生成
複雑な書式設定、カスタムスタイルゼロから作成python-docx文書モデルに直接アクセス
技術者以外がテンプレートを設計テンプレートdocxtplユーザーが Word で編集し、開発者がデータをバインド
PDF 出力が必要どちらでも可+変換libreoffice / docx2pdf後処理ステップ

python-docx のパターン

文書の作成
from docx import Document
from docx.shared import Inches, Pt, Cm, RGBColor
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT

doc = Document()

# Set default font
style = doc.styles['Normal']
font = style.font
font.name = 'Calibri'
font.size = Pt(11)

# Add heading
doc.add_heading('Monthly Report', level=0)

# Add paragraph with formatting
para = doc.add_paragraph()
run = para.add_run('Important: ')
run.bold = True
run.font.color.rgb = RGBColor(0xCC, 0x00, 0x00)
para.add_run('This section requires attention.')

# Add table
table = doc.add_table(rows=1, cols=3, style='Light Grid Accent 1')
hdr_cells = table.rows[0].cells
hdr_cells[0].text = 'Name'
hdr_cells[1].text = 'Department'
hdr_cells[2].text = 'Revenue'

for name, dept, rev in data:
    row_cells = table.add_row().cells
    row_cells[0].text = name
    row_cells[1].text = dept
    row_cells[2].text = f'${rev:,.2f}'

# Add image
doc.add_picture('chart.png', width=Inches(5.5))

# Save
doc.save('report.docx')
ヘッダーとフッター
from docx.enum.section import WD_ORIENT
from docx.oxml.ns import qn
from docx.oxml import OxmlElement

section = doc.sections[0]

# Page setup
section.page_width = Cm(21)
section.page_height = Cm(29.7)
section.left_margin = Cm(2.5)
section.right_margin = Cm(2.5)
section.top_margin = Cm(2.5)
section.bottom_margin = Cm(2.5)

# Header
header = section.header
header_para = header.paragraphs[0]
header_para.text = 'Company Name — Confidential'
header_para.alignment = WD_ALIGN_PARAGRAPH.RIGHT
header_para.style.font.size = Pt(9)
header_para.style.font.color.rgb = RGBColor(0x88, 0x88, 0x88)

# Footer with page numbers
footer = section.footer
footer_para = footer.paragraphs[0]
footer_para.alignment = WD_ALIGN_PARAGRAPH.CENTER

# Add page number field
run = footer_para.add_run()
fldChar = OxmlElement('w:fldChar')
fldChar.set(qn('w:fldCharType'), 'begin')
run._r.append(fldChar)

run2 = footer_para.add_run()
instrText = OxmlElement('w:instrText')
instrText.set(qn('xml:space'), 'preserve')
instrText.text = ' PAGE '
run2._r.append(instrText)

run3 = footer_para.add_run()
fldChar2 = OxmlElement('w:fldChar')
fldChar2.set(qn('w:fldCharType'), 'end')
run3._r.append(fldChar2)
表の書式設定
from docx.shared import Cm, Pt
from docx.oxml.ns import nsdecls
from docx.oxml import parse_xml

# Set column widths
table.columns[0].width = Cm(4)
table.columns[1].width = Cm(6)
table.columns[2].width = Cm(3)

# Cell shading
for cell in table.rows[0].cells:
    shading = parse_xml(f'<w:shd {nsdecls("w")} w:fill="2F5496"/>')
    cell._tc.get_or_add_tcPr().append(shading)
    for paragraph in cell.paragraphs:
        for run in paragraph.runs:
            run.font.color.rgb = RGBColor(0xFF, 0xFF, 0xFF)
            run.font.bold = True

# Cell alignment
for row in table.rows:
    for cell in row.cells:
        cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER

docxtpl のテンプレートパターン

テンプレート構文(Jinja2)
Template file (template.docx) contains:

{{ company_name }}
Date: {{ report_date }}

Dear {{ recipient_name }},

{% for item in items %}
- {{ item.name }}: ${{ item.price }}
{% endfor %}

Total: ${{ total }}

{%if urgent %}
URGENT: This requires immediate attention.
{%endif %}
テンプレートのレンダリング
from docxtpl import DocxTemplate, InlineImage
from docx.shared import Mm

tpl = DocxTemplate('template.docx')

context = {
    'company_name': 'Acme Corp',
    'report_date': '2025-03-15',
    'recipient_name': 'Alice Johnson',
    'items': [
        {'name': 'Widget A', 'price': '29.99'},
        {'name': 'Widget B', 'price': '49.99'},
    ],
    'total': '79.98',
    'urgent': True,
    'chart': InlineImage(tpl, 'chart.png', width=Mm(120)),
}

tpl.render(context)
tpl.save('output.docx')
テンプレート内のリッチテキスト
from docxtpl import RichText

rt = RichText()
rt.add('Normal text ')
rt.add('bold text', bold=True)
rt.add(' and ')
rt.add('red text', color='FF0000')
rt.add(' with ')
rt.add('a link', url_id=tpl.build_url_id('https://example.com'))

context = {'formatted_text': rt}
テンプレート内の表
Template table row with loop:
{% tr for row in table_data %}
{{ row.name }} | {{ row.value }} | {{ row.status }}
{% endtr %}

差し込み印刷

from docxtpl import DocxTemplate
import csv

template = DocxTemplate('letter_template.docx')

with open('recipients.csv') as f:
    reader = csv.DictReader(f)
    for i, row in enumerate(reader):
        context = {
            'name': row['name'],
            'address': row['address'],
            'amount': row['amount'],
            'due_date': row['due_date'],
        }
        template.render(context)
        template.save(f'letters/letter_{i:04d}_{row["name"]}.docx')
        template = DocxTemplate('letter_template.docx')  # Re-load for next iteration

スタイル管理

カスタムスタイル
from docx.enum.style import WD_STYLE_TYPE

# Create custom paragraph style
style = doc.styles.add_style('CustomHeading', WD_STYLE_TYPE.PARAGRAPH)
style.font.name = 'Arial'
style.font.size = Pt(16)
style.font.bold = True
style.font.color.rgb = RGBColor(0x2F, 0x54, 0x96)
style.paragraph_format.space_before = Pt(12)
style.paragraph_format.space_after = Pt(6)

# Apply custom style
doc.add_paragraph('Section Title', style='CustomHeading')
スタイルの継承
Normal → Heading 1 → Heading 2 → ...
Normal → Body Text → List Paragraph
Normal → Table Normal → Table Grid

変換方法

DOCX から PDF への変換
# Option 1: LibreOffice (most reliable, server-friendly)
import subprocess
subprocess.run([
    'libreoffice', '--headless', '--convert-to', 'pdf',
    '--outdir', output_dir, input_file
])

# Option 2: docx2pdf (Windows/macOS with Word installed)
from docx2pdf import convert
convert('input.docx', 'output.pdf')

# Option 3: Generate PDF directly with reportlab for full control

エラー処理

import jinja2

def safe_generate_document(template_path, context, output_path):
    try:
        tpl = DocxTemplate(template_path)
        tpl.render(context)
        tpl.save(output_path)
        return True
    except jinja2.UndefinedError as e:
        print(f"Missing template variable: {e}")
        return False
    except FileNotFoundError as e:
        print(f"Template not found: {e}")
        return False
    except Exception as e:
        print(f"Document generation failed: {e}")
        return False

アンチパターン/よくある間違い

アンチパターン問題が起きる理由代わりに行うこと
スタイルを使わず、フォントサイズをハードコードする書式に一貫性がなく、保守が困難になりますスタイルを一度定義し、すべての箇所に適用します
欠損したテンプレート変数を処理しないデータが不完全な場合に実行時エラーが発生しますjinja2.Undefined またはデフォルトフィルターを使用します
ページ分割を考慮せず、大きな表を作成する出力が読みにくくなり、レイアウトが崩れますページをまたいで表を分割するか、要約します
絶対画像パスを使用する環境間の移植性が損なわれます相対パスを使用するか、画像を埋め込みます
異なるバージョンの Word でテストしない書式が気付かないうちに崩れますWord、LibreOffice、Google Docs でテストします
API があるのに XML を直接変更する壊れやすく、バージョンに依存するコードになりますまず python-docx の API メソッドを使用します
スタイルを使わず、すべてを直接書式設定する一貫性を保つことができません名前付きスタイルを作成して適用します
Unicode 文字を無視する生成した文書で文字化けが発生しますアクセント付き文字、CJK、記号でテストします
差し込み印刷でテンプレートを再読み込みしない最初のレンダリング後に出力が破損します反復ごとに DocxTemplate を再インスタンス化します

合理化を防ぐガード

  • アプローチの決定(スクラッチ作成かテンプレートか)を省略しないでください。実装全体がこれによって決まります。
  • 少なくとも Word と別のビューアー 1 つでテストせずに、ドキュメントを生成しないでください。
  • データの欠落を無視しないでください。空または null のフィールドは、デフォルト値または条件付きセクションで処理してください。
  • 本番環境のドキュメント生成パイプラインで、エラー処理を省略しないでください。
  • スタイルを使用できる場合は、書式をハードコードしないでください。

統合ポイント

スキル連携方法
pdf-processingDOCX から PDF への変換、または PDF を直接生成する方法の選択
xlsx-processingExcel のデータをドキュメント生成コンテキストに取り込みます
email-composer生成したドキュメントをビジネスメールに添付します
content-research-writer調査内容をホワイトペーパーやレポート用に整形します
file-organizer出力ファイルの命名規則とディレクトリー構成
deploymentCI/CD またはサーバー環境でのドキュメント生成パイプライン

スキルの種類

柔軟 — ドキュメントの複雑さに応じて、python-docx(プログラムによる生成)と docxtpl(テンプレートベース)を選択します。シンプルなレポートではテンプレートが不要な場合もありますが、複雑で繰り返し作成するドキュメントにはテンプレートが適しています。

コメント