mcpField
D
docx

docx

github.com/golden2002ドキュメント16439 回インストール9 週間前に更新
リポジトリ

docx について

DOCX ファイルの作成、編集、分析を支援するスキルです。docx-js による生成と XML ベースの編集手順を組み合わせ、レイアウト、変更履歴、文書の検証を扱います。

主な機能

  1. 01docx-js で DOCX を作成
  2. 02内容抽出と生 XML の確認
  3. 03展開と再梱包による DOCX 編集
  4. 04変更履歴とコメントの処理
  5. 05文書構造とレイアウトの検証

活用シーン

  1. 01書式付き DOCX 文書を生成
  2. 02テキスト抽出や文書 XML の確認
  3. 03既存ファイルの変更履歴を編集

インストール

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

$npx skills add https://github.com/golden2002/legal-research-skill --skill docx

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

LICENSE.txt
scripts/
__init__.py
accept_changes.py
comment.py
scripts/office/
pack.py
scripts/office/helpers/
__init__.py
merge_runs.py
simplify_redlines.py
scripts/office/schemas/ecma/fouth-edition/
opc-contentTypes.xsd
opc-coreProperties.xsd
opc-digSig.xsd
opc-relationships.xsd
scripts/office/schemas/ISO-IEC29500-4_2016/
dml-chart.xsd
dml-chartDrawing.xsd
dml-diagram.xsd
dml-lockedCanvas.xsd
dml-main.xsd
dml-picture.xsd
dml-spreadsheetDrawing.xsd
dml-wordprocessingDrawing.xsd
pml.xsd
shared-additionalCharacteristics.xsd
shared-bibliography.xsd
shared-commonSimpleTypes.xsd
shared-customXmlDataProperties.xsd
shared-customXmlSchemaProperties.xsd
shared-documentPropertiesCustom.xsd
shared-documentPropertiesExtended.xsd
shared-documentPropertiesVariantTypes.xsd
shared-math.xsd

詳細

DOCX の作成、編集、分析

概要

.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,
        InternalHyperlink, Bookmark, FootnoteReferenceRun, PositionalTab,
        PositionalTabAlignment, PositionalTabRelativeTo, PositionalTabLeader,
        TabStopType, TabStopPosition, Column, SectionType,
        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 Letter12,24015,8409,360
A4(デフォルト)11,90616,8389,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 ドキュメントで動作しません。

// 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 ドキュメントと互換性がありません)
  • 表の幅は 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")] })
ハイパーリンク
// External link
new Paragraph({
  children: [new ExternalHyperlink({
    children: [new TextRun({ text: "Click here", style: "Hyperlink" })],
    link: "https://example.com",
  })]
})

// Internal link (bookmark + reference)
// 1. Create bookmark at destination
new Paragraph({ heading: HeadingLevel.HEADING_1, children: [
  new Bookmark({ id: "chapter1", children: [new TextRun("Chapter 1")] }),
]})
// 2. Link to it
new Paragraph({ children: [new InternalHyperlink({
  children: [new TextRun({ text: "See Chapter 1", style: "Hyperlink" })],
  anchor: "chapter1",
})]})
脚注
const doc = new Document({
  footnotes: {
    1: { children: [new Paragraph("Source: Annual Report 2024")] },
    2: { children: [new Paragraph("See appendix for methodology")] },
  },
  sections: [{
    children: [new Paragraph({
      children: [
        new TextRun("Revenue grew 15%"),
        new FootnoteReferenceRun(1),
        new TextRun(" using adjusted metrics"),
        new FootnoteReferenceRun(2),
      ],
    })]
  }]
});
タブストップ
// Right-align text on same line (e.g., date opposite a title)
new Paragraph({
  children: [
    new TextRun("Company Name"),
    new TextRun("\tJanuary 2025"),
  ],
  tabStops: [{ type: TabStopType.RIGHT, position: TabStopPosition.MAX }],
})

// Dot leader (e.g., TOC-style)
new Paragraph({
  children: [
    new TextRun("Introduction"),
    new TextRun({ children: [
      new PositionalTab({
        alignment: PositionalTabAlignment.RIGHT,
        relativeTo: PositionalTabRelativeTo.MARGIN,
        leader: PositionalTabLeader.DOT,
      }),
      "3",
    ]}),
  ],
})
多段組みレイアウト
// Equal-width columns
sections: [{
  properties: {
    column: {
      count: 2,          // number of columns
      space: 720,        // gap between columns in DXA (720 = 0.5 inch)
      equalWidth: true,
      separate: true,    // vertical line between columns
    },
  },
  children: [/* content flows naturally across columns */]
}]

// Custom-width columns (equalWidth must be false)
sections: [{
  properties: {
    column: {
      equalWidth: false,
      children: [
        new Column({ width: 5400, space: 720 }),
        new Column({ width: 3240 }),
      ],
    },
  },
  children: [/* content */]
}]

type: SectionType.NEXT_COLUMN を指定した新しいセクションで、段区切りを強制します。

目次
// 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 ドキュメントで表示が崩れます)
  • テーブルには 2 種類の幅が必要 - columnWidths 配列とセルの width の両方を指定し、値を一致させてください
  • テーブルの幅 = columnWidths の合計 - DXA の場合、合計値が正確に一致するようにしてください
  • 必ずセルの余白を設定する - 読みやすい余白のために margins: { top: 80, bottom: 80, left: 120, right: 120 } を使用してください
  • ShadingType.CLEAR を使用する - テーブルの塗りつぶしに SOLID は使用しないでください
  • テーブルを区切り線として使用しない - セルには最小高さがあり、空の枠として描画されます(ヘッダーやフッターでも同様です)。代わりに Paragraph に border: { bottom: { style: BorderStyle.SINGLE, size: 6, color: "2E75B6", space: 1 } } を設定してください。2 列のフッターには、テーブルではなくタブ位置(タブ位置のセクションを参照)を使用してください
  • TOC には HeadingLevel のみを使用する - 見出しの段落にカスタムスタイルを設定しないでください
  • 組み込みスタイルを上書きする - "Heading1"、"Heading2" などの正確な ID を使用してください
  • outlineLevel を含める - TOC に必要です(見出し 1 は 0、見出し 2 は 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&#x2019;s a quote: &#x201C;Hello&#x201D;</w:t>
エンティティ文字
&#x2018;‘(左シングルクォート)
&#x2019;’(右シングルクォート / アポストロフィ)
&#x201C;“(左ダブルクォート)
&#x201D;”(右ダブルクォート)

コメントの追加: 複数の XML ファイルにまたがる定型処理には comment.py を使用してください(テキストは事前に XML エスケープされている必要があります):

python scripts/comment.py unpacked/ 0 "Comment text with &amp; and &#x2019;"
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: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>
画像
  1. 画像ファイルを word/media/ に追加します
  2. word/_rels/document.xml.rels にリレーションシップを追加します:
<Relationship Id="rId5" Type=".../image" Target="media/image1.png"/>
  1. [Content_Types].xml にコンテンツタイプを追加します:
<Default Extension="png" ContentType="image/png"/>
  1. 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>

依存関係

  • pandoc: テキストの抽出
  • docx: npm install -g docx(新規ドキュメント用)
  • LibreOffice: PDF 変換(scripts/office/soffice.py を介してサンドボックス環境向けに自動設定されます)
  • Poppler: 画像用の pdftoppm

コメント