docx について
DOCXファイルの作成、編集、分析を支援するスキルです。テキスト、XML、レイアウト検証を含む文書作業向けに、一般的な操作手順を案内します。
主な機能
- 01docx-jsによるDOCX作成
- 02テキスト抽出とXML確認
- 03XMLを使った既存ファイルの編集
- 04DOCXからPDFや画像への変換
- 05変更履歴の反映とファイル検証
活用シーン
- 01新しいDOCX文書の作成
- 02文書内容の抽出や分析
- 03既存DOCXファイルの変更
- 04視覚的な確認用に文書を出力
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ agentscope-ai/ qwenpaw --skill docxインストール後、Claude Code で/docxを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
LICENSE.txtscripts/__init__.pyaccept_changes.pycomment.pyscripts/office/pack.pyscripts/office/helpers/__init__.pymerge_runs.pysimplify_redlines.pyscripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsdopc-coreProperties.xsdopc-digSig.xsdopc-relationships.xsdscripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsddml-chartDrawing.xsddml-diagram.xsddml-lockedCanvas.xsddml-main.xsddml-picture.xsddml-spreadsheetDrawing.xsddml-wordprocessingDrawing.xsdpml.xsdshared-additionalCharacteristics.xsdshared-bibliography.xsdshared-commonSimpleTypes.xsdshared-customXmlDataProperties.xsdshared-customXmlSchemaProperties.xsdshared-documentPropertiesCustom.xsdshared-documentPropertiesExtended.xsdshared-documentPropertiesVariantTypes.xsdshared-math.xsd詳細
重要: すべての
scripts/パスは、このスキルディレクトリからの相対パスです。 次のコマンドで実行します:cd {this_skill_dir} && python scripts/...または、execute_shell_commandのcwdパラメーターを使用します。
DOCX の作成、編集、分析
前提条件
- docx(
npm install -g docx):新しいドキュメントの作成 - LibreOffice(
soffice):.docから.docxへの変換、変更履歴の承認、PDF へのエクスポート - pandoc:テキストの抽出
- pdftoppm(poppler-utils):ドキュメントを画像に変換するワークフロー
pdftoppmを利用できない場合、Python の代替手段としてpdf2imageを使用できます。- Windows では、依存関係をインストールし、
PATHから利用できるようにする必要があります。不足している場合は、依存関係の問題を報告して処理を停止してください(再試行を続けないでください)。
概要
.docx ファイルは、XML ファイルを含む ZIP アーカイブです。
クイックリファレンス
| タスク | 方法 |
|---|---|
| 内容の読み取り/分析 | pandoc を使用するか、展開して生の XML を確認 |
| 新しいドキュメントの作成 | docx-js を使用 —「新しいドキュメントの作成」を参照 |
| 既存のドキュメントの編集 | 展開 → XML を編集 → 再パッケージ —「既存のドキュメントの編集」を参照 |
.doc から .docx への変換
従来の .doc ファイルは、編集前に変換する必要があります。
python scripts/office/soffice.py --headless --convert-to docx document.doc
内容の読み取り
# Text extraction with tracked changes
pandoc --track-changes=all document.docx -o output.md
# Raw XML access
python scripts/office/unpack.py document.docx unpacked/
画像への変換
python scripts/office/soffice.py --headless --convert-to pdf document.docx
pdftoppm -jpeg -r 150 document.pdf page
変更履歴の承認
すべての変更履歴を承認した、クリーンなドキュメントを生成するには(LibreOffice が必要です):
python scripts/accept_changes.py input.docx output.docx
新しいドキュメントの作成
JavaScript で .docx ファイルを生成してから、検証します。インストール:npm install -g docx
セットアップ
const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, ImageRun,
Header, Footer, AlignmentType, PageOrientation, LevelFormat, ExternalHyperlink,
TableOfContents, HeadingLevel, BorderStyle, WidthType, ShadingType,
VerticalAlign, PageNumber, PageBreak } = require('docx');
const doc = new Document({ sections: [{ children: [/* content */] }] });
Packer.toBuffer(doc).then(buffer => fs.writeFileSync("doc.docx", buffer));
検証
ファイルを作成したら、検証してください。検証に失敗した場合は、展開して XML を修正し、再パッケージしてください。
python scripts/office/validate.py doc.docx
ページサイズ
// CRITICAL: docx-js defaults to A4, not US Letter
// Always set page size explicitly for consistent results
sections: [{
properties: {
page: {
size: {
width: 12240, // 8.5 inches in DXA
height: 15840 // 11 inches in DXA
},
margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } // 1 inch margins
}
},
children: [/* content */]
}]
一般的な用紙サイズ(DXA 単位、1440 DXA = 1 インチ):
| 用紙 | 幅 | 高さ | コンテンツ幅(余白 1 インチ) |
|---|---|---|---|
| US Letter | 12,240 | 15,840 | 9,360 |
| A4(デフォルト) | 11,906 | 16,838 | 9,026 |
横向き: docx-js は内部で幅と高さを入れ替えるため、縦向きの寸法を渡し、入れ替えは docx-js に任せてください。
size: {
width: 12240, // Pass SHORT edge as width
height: 15840, // Pass LONG edge as height
orientation: PageOrientation.LANDSCAPE // docx-js swaps them in the XML
},
// Content width = 15840 - left margin - right margin (uses the long edge)
スタイル(組み込みの見出しスタイルを上書き)
デフォルトのフォントには、広くサポートされている Arial を使用してください。読みやすさを保つため、タイトルは黒にしてください。
const doc = new Document({
styles: {
default: { document: { run: { font: "Arial", size: 24 } } }, // 12pt default
paragraphStyles: [
// IMPORTANT: Use exact IDs to override built-in styles
{ id: "Heading1", name: "Heading 1", basedOn: "Normal", next: "Normal", quickFormat: true,
run: { size: 32, bold: true, font: "Arial" },
paragraph: { spacing: { before: 240, after: 240 }, outlineLevel: 0 } }, // outlineLevel required for TOC
{ id: "Heading2", name: "Heading 2", basedOn: "Normal", next: "Normal", quickFormat: true,
run: { size: 28, bold: true, font: "Arial" },
paragraph: { spacing: { before: 180, after: 180 }, outlineLevel: 1 } },
]
},
sections: [{
children: [
new Paragraph({ heading: HeadingLevel.HEADING_1, children: [new TextRun("Title")] }),
]
}]
});
リスト(Unicode の箇条書きは絶対に使用しない)
// ❌ WRONG - never manually insert bullet characters
new Paragraph({ children: [new TextRun("• Item")] }) // BAD
new Paragraph({ children: [new TextRun("\u2022 Item")] }) // BAD
// ✅ CORRECT - use numbering config with LevelFormat.BULLET
const doc = new Document({
numbering: {
config: [
{ reference: "bullets",
levels: [{ level: 0, format: LevelFormat.BULLET, text: "•", alignment: AlignmentType.LEFT,
style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] },
{ reference: "numbers",
levels: [{ level: 0, format: LevelFormat.DECIMAL, text: "%1.", alignment: AlignmentType.LEFT,
style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] },
]
},
sections: [{
children: [
new Paragraph({ numbering: { reference: "bullets", level: 0 },
children: [new TextRun("Bullet item")] }),
new Paragraph({ numbering: { reference: "numbers", level: 0 },
children: [new TextRun("Numbered item")] }),
]
}]
});
// ⚠️ Each reference creates INDEPENDENT numbering
// Same reference = continues (1,2,3 then 4,5,6)
// Different reference = restarts (1,2,3 then 1,2,3)
表
重要:表には 2 か所で幅を指定する必要があります — 表の columnWidths と各セルの width の両方を設定してください。両方を指定しないと、一部のプラットフォームで表が正しく表示されません。
// CRITICAL: Always set table width for consistent rendering
// CRITICAL: Use ShadingType.CLEAR (not SOLID) to prevent black backgrounds
const border = { style: BorderStyle.SINGLE, size: 1, color: "CCCCCC" };
const borders = { top: border, bottom: border, left: border, right: border };
new Table({
width: { size: 9360, type: WidthType.DXA }, // Always use DXA (percentages break in Google Docs)
columnWidths: [4680, 4680], // Must sum to table width (DXA: 1440 = 1 inch)
rows: [
new TableRow({
children: [
new TableCell({
borders,
width: { size: 4680, type: WidthType.DXA }, // Also set on each cell
shading: { fill: "D5E8F0", type: ShadingType.CLEAR }, // CLEAR not SOLID
margins: { top: 80, bottom: 80, left: 120, right: 120 }, // Cell padding (internal, not added to width)
children: [new Paragraph({ children: [new TextRun("Cell")] })]
})
]
})
]
})
表の幅の計算:
常に WidthType.DXA を使用してください — WidthType.PERCENTAGE は Google Docs で正しく動作しません。
// Table width = sum of columnWidths = content width
// US Letter with 1" margins: 12240 - 2880 = 9360 DXA
width: { size: 9360, type: WidthType.DXA },
columnWidths: [7000, 2360] // Must sum to table width
幅のルール:
- 常に
WidthType.DXAを使用してください —WidthType.PERCENTAGEは使用しないでください(Google Docs と互換性がありません) - 表の幅は
columnWidthsの合計と一致させてください - セルの
widthは、対応するcolumnWidthと一致させてください - セルの
marginsは内部の余白です。セルの幅に加算されるのではなく、コンテンツ領域を縮小します - ページ幅いっぱいの表では、コンテンツ幅(ページ幅から左右の余白を差し引いた幅)を使用してください
画像
// CRITICAL: type parameter is REQUIRED
new Paragraph({
children: [new ImageRun({
type: "png", // Required: png, jpg, jpeg, gif, bmp, svg
data: fs.readFileSync("image.png"),
transformation: { width: 200, height: 150 },
altText: { title: "Title", description: "Desc", name: "Name" } // All three required
})]
})
改ページ
// CRITICAL: PageBreak must be inside a Paragraph
new Paragraph({ children: [new PageBreak()] })
// Or use pageBreakBefore
new Paragraph({ pageBreakBefore: true, children: [new TextRun("New page")] })
目次
// CRITICAL: Headings must use HeadingLevel ONLY - no custom styles
new TableOfContents("Table of Contents", { hyperlink: true, headingStyleRange: "1-3" })
ヘッダー/フッター
sections: [{
properties: {
page: { margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } } // 1440 = 1 inch
},
headers: {
default: new Header({ children: [new Paragraph({ children: [new TextRun("Header")] })] })
},
footers: {
default: new Footer({ children: [new Paragraph({
children: [new TextRun("Page "), new TextRun({ children: [PageNumber.CURRENT] })]
})] })
},
children: [/* content */]
}]
docx-js に関する重要なルール
- ページサイズを明示的に設定する - docx-js のデフォルトは A4 です。米国向けの文書では US Letter(12240 x 15840 DXA)を使用してください
- 横向きでは縦向きの寸法を渡す - docx-js は内部で幅と高さを入れ替えます。短辺を
width、長辺をheightとして渡し、orientation: PageOrientation.LANDSCAPEを設定してください \nは使用しない - 個別の Paragraph 要素を使用してください- Unicode の箇条書き記号は使用しない - 番号設定で
LevelFormat.BULLETを使用してください - PageBreak は Paragraph 内に配置する - 単独で配置すると無効な XML が生成されます
- ImageRun には
typeが必要 - png、jpg などを必ず指定してください - テーブルの
widthは必ず DXA で設定する -WidthType.PERCENTAGEは使用しないでください(Google Docs で問題が発生します) - テーブルには幅を 2 か所で指定する必要がある -
columnWidths配列とセルのwidthの両方を指定し、値を一致させてください - テーブル幅は
columnWidthsの合計と一致させる - DXA の場合、合計が正確に一致するようにしてください - セルの余白は必ず追加する - 読みやすい余白にするには
margins: { top: 80, bottom: 80, left: 120, right: 120 }を使用してください ShadingType.CLEARを使用する - テーブルの網かけに SOLID は使用しないでください- 目次には HeadingLevel のみが必要 - 見出し段落にカスタムスタイルを設定しないでください
- 組み込みスタイルを上書きする - 正確な ID("Heading1"、"Heading2" など)を使用してください
outlineLevelを含める - 目次に必須です(H1 は 0、H2 は 1 など)
既存の文書を編集する
次の 3 つの手順を順番に実行してください。
手順 1:展開
python scripts/office/unpack.py document.docx unpacked/
XML を抽出して整形し、隣接する run を結合し、スマートクォートを XML エンティティ(“ など)に変換して、編集後も保持されるようにします。run の結合を省略するには --merge-runs false を使用してください。
手順 2:XML を編集する
unpacked/word/ 内のファイルを編集します。パターンについては、以下の「XML リファレンス」を参照してください。
変更履歴とコメントの作成者には、ユーザーが別の名前を明示的に指定していない限り、"Claude" を使用してください。
文字列の置換には Edit ツールを直接使用してください。Python スクリプトは作成しないでください。 スクリプトを使うと、不必要に複雑になります。Edit ツールでは、置換対象が正確に表示されます。
重要:新しい内容にはスマートクォートを使用してください。 アポストロフィや引用符を含むテキストを追加する場合は、XML エンティティを使用してスマートクォートを出力してください。
<w:t>Here’s a quote: “Hello”</w:t>
| エンティティ | 文字 |
|---|---|
‘ | ‘(左シングル) |
’ | ’(右シングル/アポストロフィ) |
“ | “(左ダブル) |
” | ”(右ダブル) |
コメントの追加: 複数の XML ファイルにまたがる定型処理には comment.py を使用してください(テキストは事前に XML エスケープしておく必要があります)。
python scripts/comment.py unpacked/ 0 "Comment text with & and ’"
python scripts/comment.py unpacked/ 1 "Reply text" --parent 0 # reply to comment 0
python scripts/comment.py unpacked/ 0 "Text" --author "Custom Author" # custom author name
その後、document.xml にマーカーを追加します(「XML リファレンス」の「コメント」を参照)。
手順 3:パック
python scripts/office/pack.py unpacked/ output.docx --original document.docx
自動修復を行いながら検証し、XML を圧縮して DOCX を作成します。検証を省略するには --validate false を使用してください。
自動修復で修正されるもの:
durableIdが 0x7FFFFFFF 以上(有効な ID を再生成します)- 空白を含む
<w:t>にxml:space="preserve"がない
自動修復で修正されないもの:
- 不正な XML、無効な要素の入れ子、リレーションシップの欠落、スキーマ違反
よくある落とし穴
<w:r>要素全体を置き換える:変更履歴を追加する際は、<w:r>...</w:r>ブロック全体を、兄弟要素となる<w:del>...<w:ins>...に置き換えてください。run の中に変更履歴タグを挿入しないでください。<w:rPr>の書式を保持する:太字やフォントサイズなどを維持するため、元の run の<w:rPr>ブロックを変更履歴の run にコピーしてください。
XML リファレンス
スキーマへの準拠
<w:pPr>内の要素の順序:<w:pStyle>、<w:numPr>、<w:spacing>、<w:ind>、<w:jc>、最後に<w:rPr>- 空白:先頭または末尾に空白がある
<w:t>にはxml:space="preserve"を追加してください - RSID:8 桁の 16 進数である必要があります(例:
00AB1234)
変更履歴
挿入:
<w:ins w:id="1" w:author="Claude" w:date="2025-01-01T00:00:00Z">
<w:r><w:t>inserted text</w:t></w:r>
</w:ins>
削除:
<w:del w:id="2" w:author="Claude" w:date="2025-01-01T00:00:00Z">
<w:r><w:delText>deleted text</w:delText></w:r>
</w:del>
<w:del> の内部: <w:t> の代わりに <w:delText> を、<w:instrText> の代わりに <w:delInstrText> を使用します。
最小限の編集 — 変更箇所だけにマークを付けます:
<w:r><w:t>The term is </w:t></w:r>
<w:del w:id="1" w:author="Claude" w:date="...">
<w:r><w:delText>30</w:delText></w:r>
</w:del>
<w:ins w:id="2" w:author="Claude" w:date="...">
<w:r><w:t>60</w:t></w:r>
</w:ins>
<w:r><w:t> days.</w:t></w:r>
段落/リスト項目全体を削除する場合 — 段落の内容をすべて削除するときは、次の段落と結合されるよう、段落記号にも削除マークを付けます。<w:pPr><w:rPr> 内に <w:del/> を追加します:
<w:p>
<w:pPr>
<w:numPr>...</w:numPr>
<w:rPr>
<w:del w:id="1" w:author="Claude" w:date="2025-01-01T00:00:00Z"/>
</w:rPr>
</w:pPr>
<w:del w:id="2" w:author="Claude" w:date="2025-01-01T00:00:00Z">
<w:r><w:delText>Entire paragraph content being deleted...</w:delText></w:r>
</w:del>
</w:p>
<w:pPr><w:rPr> 内に <w:del/> がないと、変更を承諾したときに空の段落/リスト項目が残ります。
別の作成者による挿入を却下する場合 — その挿入の内部に削除をネストします:
<w:ins w:author="Jane" w:id="5">
<w:del w:author="Claude" w:id="10">
<w:r><w:delText>their inserted text</w:delText></w:r>
</w:del>
</w:ins>
別の作成者による削除を復元する場合 — その削除を変更せず、後ろに挿入を追加します:
<w:del w:author="Jane" w:id="5">
<w:r><w:delText>deleted text</w:delText></w:r>
</w:del>
<w:ins w:author="Claude" w:id="10">
<w:r><w:t>deleted text</w:t></w:r>
</w:ins>
コメント
comment.py の実行後(ステップ 2 を参照)、document.xml にマーカーを追加します。返信には --parent フラグを使用し、親のマーカー内にネストします。
重要:<w:commentRangeStart> と <w:commentRangeEnd> は <w:r> の子ではなく、兄弟要素です。
<w:commentRangeStart w:id="0"/>
<w:del w:id="1" w:author="Claude" w:date="2025-01-01T00:00:00Z">
<w:r><w:delText>deleted</w:delText></w:r>
</w:del>
<w:r><w:t> more text</w:t></w:r>
<w:commentRangeEnd w:id="0"/>
<w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="0"/></w:r>
<w:commentRangeStart w:id="0"/>
<w:commentRangeStart w:id="1"/>
<w:r><w:t>text</w:t></w:r>
<w:commentRangeEnd w:id="1"/>
<w:commentRangeEnd w:id="0"/>
<w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="0"/></w:r>
<w:r><w:rPr><w:rStyle w:val="CommentReference"/></w:rPr><w:commentReference w:id="1"/></w:r>
画像
- 画像ファイルを
word/media/に追加します word/_rels/document.xml.relsにリレーションシップを追加します:
<Relationship Id="rId5" Type=".../image" Target="media/image1.png"/>
[Content_Types].xmlにコンテンツタイプを追加します:
<Default Extension="png" ContentType="image/png"/>
- document.xml 内で参照します:
<w:drawing>
<wp:inline>
<wp:extent cx="914400" cy="914400"/>
<a:graphic>
<a:graphicData uri=".../picture">
<pic:pic>
<pic:blipFill><a:blip r:embed="rId5"/></pic:blipFill>
</pic:pic>
</a:graphicData>
</a:graphic>
</wp:inline>
</w:drawing>