Claude 官方 DOCX Skill 深度解析
技术栈对比速查表
| 对比维度 | docx-js | python-docx / Document 类 | pandoc | LibreOffice | Poppler |
|---|---|---|---|---|---|
| 语言 | JavaScript/TypeScript | Python | Haskell (CLI) | C++ (CLI) | C (CLI) |
| 运行环境 | Node.js / 浏览器 | Python 3.x | 终端命令行 | 终端命令行 | 终端命令行 |
| 主要用途 | 创建新文档 | 编辑/追踪修改/批注 | 文本提取/格式转换 | DOCX → PDF | PDF → 图片 |
| ⭐ MD → DOCX | ✅ 需编程构建 | ✅ 需编程构建 | ✅ 一键转换 | ⚠️ 需先转 HTML | ❌ 不支持 |
| 适用场景 | 从零生成 Word | 修改现有文档 | 读取文档内容 | 文档预览 | 可视化对比 |
| 支持追踪修改 | ❌ 不支持 | ✅ 完整支持 | ✅ 可读取 | - | - |
| 支持批注 | ❌ 不支持 | ✅ 完整支持 | ✅ 可读取 | - | - |
| 保持原格式 | - (新建文档) | ✅ 完整保持 | ❌ 转为纯文本 | ✅ 高保真 | - |
| API 风格 | 声明式、直观 | 命令式、DOM 操作 | CLI 参数 | CLI 参数 | CLI 参数 |
| 学习曲线 | ⭐⭐ 简单 | ⭐⭐⭐ 中等 | ⭐ 简单 | ⭐ 简单 | ⭐ 简单 |
| 安装方式 | npm install docx | pip install defusedxml | apt install pandoc | apt install libreoffice | apt install poppler-utils |
| 核心命令/API | Packer.toBuffer() | Document().save() | pandoc x.docx -o x.md | soffice --convert-to pdf | pdftoppm -jpeg |
| 输出格式 | .docx 二进制 | .docx 二进制 | Markdown/HTML/等 | JPEG/PNG | |
| Claude 环境 | ✅ 沙箱可执行 | ✅ 沙箱可执行 | ✅ 预装可用 | ✅ 预装可用 | ✅ 预装可用 |
| API 调用环境 | ❌ 需后端执行 | ❌ 需后端执行 | ❌ 需后端执行 | ❌ 需后端执行 | ❌ 需后端执行 |
场景选择指南
| 你想做什么 | 首选工具 | 备选方案 | 命令/说明 |
|---|---|---|---|
| ⭐ MD → DOCX (简单) | pandoc | - | pandoc input.md -o output.docx |
| ⭐ MD → DOCX (精美排版) | docx-js | python-docx | 需编程,可控制样式/页眉/目录 |
| 修改合同/保留格式 | python-docx | - | 保持原文档所有格式 |
| 法律红线审阅 | python-docx | - | <w:ins>/<w:del> 追踪修改 |
| 添加审阅批注 | python-docx | - | 操作 comments.xml |
| 提取文档文本 | pandoc | python-docx | pandoc x.docx -o x.md |
| 文档转 PDF | LibreOffice | - | soffice --convert-to pdf |
| PDF 转图片预览 | Poppler | ImageMagick | pdftoppm -jpeg -r 150 |
核心功能概览
Claude 官方 DOCX Skill 提供了 7 大核心功能,覆盖 Word 文档处理的完整生命周期:
┌─────────────────────────────────────────────────────────────────────────┐
│ DOCX Skill 核心功能矩阵 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 1. 创建 │ │ 2. 编辑 │ │ 3. 分析 │ │
│ │ 新文档 │ │ 现有文档 │ │ 文档内容 │ │
│ │ (docx-js) │ │ (Python) │ │ (pandoc) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 4. 追踪 │ │ 5. 添加 │ │ 6. 文档 │ │
│ │ 修改 │ │ 批注 │ │ 验证 │ │
│ │ (Redlining) │ │ (Comments) │ │ (Schema) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────┐ │
│ │ 7. 转换 │ │
│ │ 为图片 │ │
│ │ (可视化) │ │
│ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘功能详解
| 序号 | 功能名称 | 技术实现 | 典型场景 |
|---|---|---|---|
| 1 | 创建新文档 | JavaScript docx 库 | 从 Markdown/文本生成专业 Word 文档 |
| 2 | 编辑现有文档 | Python Document 类 | 修改已有文档的内容、格式、结构 |
| 3 | 分析文档内容 | pandoc 转 Markdown | 提取文本、理解文档结构、读取批注 |
| 4 | 追踪修改 | OOXML <w:ins>/<w:del> | 法律合同审阅、多人协作编辑 |
| 5 | 添加批注 | comments.xml 操作 | 文档审核、反馈意见、代码审查报告 |
| 6 | 文档验证 | XSD Schema + 红线验证 | 确保文档符合 OOXML 标准、可正常打开 |
| 7 | 转换为图片 | LibreOffice + pdftoppm | 文档可视化预览、截图对比 |
技术栈分工
创建文档 ──────────────────> docx-js (JavaScript/TypeScript)
├── Document, Paragraph, TextRun
├── Table, TableRow, TableCell
├── 样式系统、页眉页脚
└── Packer.toBuffer() 输出
编辑/追踪/批注 ────────────> Python Document 类
├── 解包 .docx 为 XML 目录
├── DOM 操作 + 自动属性注入
├── 追踪修改 (ins/del 标签)
├── 批注管理 (comments.xml)
└── 重新打包 + 验证
文本提取 ─────────────────> pandoc
└── pandoc --track-changes=all file.docx -o output.md
文档转图片 ────────────────> LibreOffice + Poppler
├── soffice --convert-to pdf
└── pdftoppm -jpeg -r 150为什么需要两套技术栈?
| 场景 | 选择 | 原因 |
|---|---|---|
| 创建新文档 | docx-js | API 简洁直观,适合构建文档结构 |
| 编辑现有文档 | Python | 需要保持原有格式、处理复杂 XML 结构 |
| 追踪修改 | Python | 需要精确操作 XML 节点,保持文档完整性 |
设计哲学:创建用声明式 API(docx-js),编辑用命令式操作(Python DOM)。各取所长,互补优势。
docx-js 运行环境详解
问题:JavaScript 代码在哪里运行?
docx-js 是一个 Node.js 库,需要 JavaScript 运行时来执行。它可以在以下环境运行:
┌─────────────────────────────────────────────────────────────────┐
│ docx-js 可运行的环境 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Node.js 服务端 │ │ 浏览器端 │ │
│ │ (后端运行) │ │ (前端运行) │ │
│ └─────────────────┘ └─────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ Packer.toBuffer() Packer.toBlob() │
│ → 写入文件系统 → 触发下载 │
│ │
└─────────────────────────────────────────────────────────────────┘在 claude.ai 中如何运行
Claude 有内置的代码执行沙箱(类似 Node.js 环境),可以直接执行 JavaScript:
用户请求 → Claude 生成 JS 代码 → 沙箱执行 → 生成 .docx → Artifacts 下载在 FastAPI + Next.js 环境中的 3 种方案
方案 A:利用 Next.js 的 API Routes(推荐)
Next.js 本身就运行在 Node.js 上,所以可以直接使用 docx-js:
┌──────────────────────────────────────────────────────────────┐
│ 方案 A 架构 │
├──────────────────────────────────────────────────────────────┤
│ │
│ 浏览器 │
│ │ │
│ │ POST /api/generate-docx │
│ ▼ │
│ ┌──────────────────────────────────────────┐ │
│ │ Next.js API Route │ │
│ │ (Node.js 环境) │ │
│ │ │ │
│ │ import { Document, Packer } from 'docx'│ │
│ │ const doc = new Document({...}) │ │
│ │ const buffer = await Packer.toBuffer() │ │
│ │ return new Response(buffer) │ │
│ └──────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘代码示例(App Router):
// app/api/generate-docx/route.js
import { Document, Packer, Paragraph, TextRun, HeadingLevel } from 'docx';
export async function POST(request) {
const { title, content } = await request.json();
const doc = new Document({
sections: [{
children: [
new Paragraph({
heading: HeadingLevel.HEADING_1,
children: [new TextRun({ text: title, bold: true })]
}),
new Paragraph({
children: [new TextRun(content)]
})
]
}]
});
const buffer = await Packer.toBuffer(doc);
return new Response(buffer, {
headers: {
'Content-Type': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'Content-Disposition': 'attachment; filename="document.docx"'
}
});
}方案 B:在 FastAPI 用 python-docx 替代
如果你更倾向于把逻辑集中在 FastAPI,可以用 python-docx 替代 docx-js:
# FastAPI 后端
from docx import Document
from docx.shared import Pt
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import io
app = FastAPI()
@app.post("/generate-docx")
async def generate_docx(title: str, content: str):
doc = Document()
doc.add_heading(title, level=1)
doc.add_paragraph(content)
buffer = io.BytesIO()
doc.save(buffer)
buffer.seek(0)
return StreamingResponse(
buffer,
media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
headers={"Content-Disposition": "attachment; filename=document.docx"}
)方案 C:独立 Node.js 微服务
如果需要复杂的文档生成逻辑,可以部署独立的 Node.js 服务:
┌─────────────────────────────────────────────────────────────┐
│ 方案 C 架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Next.js 前端 ──> FastAPI 后端 ──> Node.js 文档服务 │
│ │ │ │
│ │ ▼ │
│ Claude API docx-js 生成文档 │
│ (内容生成) (文件生成) │
│ │
└─────────────────────────────────────────────────────────────┘方案选择建议
| 你的情况 | 推荐方案 | 原因 |
|---|---|---|
| 简单文档生成 | 方案 A | Next.js 本身就是 Node.js,零额外配置 |
| 逻辑集中在 Python | 方案 B | python-docx 功能完整,无需跨语言调用 |
| 需要 docx-js 高级特性 | 方案 C | 独立服务,便于维护和扩展 |
| 追踪修改/红线审阅 | 方案 B | 必须用 Python,docx-js 不支持此功能 |
典型使用场景示例
场景 1:从 Markdown 生成专业报告
用户需求:"帮我把这份 Markdown 格式的周报转成 Word 文档,要有目录、页眉页脚"
Claude 执行流程:
用户提供 Markdown ──> Claude 读取 docx-js.md 学习 API
│
▼
生成 JavaScript 代码
│
▼
new Document({
sections: [{
headers: { default: new Header({...}) },
children: [
new TableOfContents("目录"),
new Paragraph({ heading: HeadingLevel.HEADING_1, ... }),
...
]
}]
})
│
▼
Packer.toBuffer(doc) ──> 输出 .docx 文件场景 2:法律合同红线审阅
用户需求:"审阅这份合同,把付款期限从 30 天改成 45 天,保留修改痕迹"
Claude 执行流程:
收到合同 .docx ──> 用 pandoc 转 Markdown 理解内容
│
▼
python unpack.py contract.docx ./unpacked
│
▼
使用 Document 类定位文本:
node = doc["word/document.xml"].get_node(contains="30 days")
│
▼
创建追踪修改:
<w:del><w:delText>30</w:delText></w:del>
<w:ins><w:t>45</w:t></w:ins>
│
▼
python pack.py ./unpacked reviewed.docxWord 中的效果:
30天 → 45 天(带修改痕迹,可接受/拒绝)
场景 3:批量添加审阅批注
用户需求:"帮我审阅这份技术文档,在有问题的地方添加批注"
Claude 执行流程:
doc = Document('unpacked', author="Technical Reviewer")
# 找到有问题的段落
para1 = doc["word/document.xml"].get_node(tag="w:p", contains="deprecated API")
doc.add_comment(start=para1, end=para1, text="这个 API 已废弃,建议使用 v2 版本")
para2 = doc["word/document.xml"].get_node(tag="w:p", contains="hardcoded value")
doc.add_comment(start=para2, end=para2, text="建议将硬编码改为配置项")
doc.save()场景 4:提取文档内容进行分析
用户需求:"帮我总结这份 50 页 Word 文档的要点"
Claude 执行流程:
# 提取文本(保留结构)
pandoc document.docx -o content.md
# 如果需要看批注
pandoc --track-changes=all document.docx -o content_with_comments.md然后 Claude 阅读 Markdown 内容,生成摘要。
场景 5:文档可视化对比
用户需求:"帮我对比修改前后的文档差异"
Claude 执行流程:
# 将两个版本转为图片
soffice --headless --convert-to pdf original.docx
soffice --headless --convert-to pdf modified.docx
pdftoppm -jpeg -r 150 original.pdf original-page
pdftoppm -jpeg -r 150 modified.pdf modified-page
# Claude 可以直接查看图片进行可视化对比场景适用性速查表
| 你想做什么 | 使用哪个功能 | 关键命令/API |
|---|---|---|
| Markdown → Word | 创建新文档 | new Document({ sections: [...] }) |
| 修改合同条款 | 追踪修改 | doc.replace_node() + <w:ins>/<w:del> |
| 添加审阅意见 | 添加批注 | doc.add_comment(start, end, text) |
| 提取文档文本 | 文本提取 | pandoc file.docx -o output.md |
| 查看文档样式 | 原始 XML | unpack.py → 查看 word/styles.xml |
| 批量替换内容 | 编辑文档 | doc.get_node() + doc.replace_node() |
| 文档截图 | 转换图片 | soffice + pdftoppm |
核心问题解答:为什么在不同环境中效果差异巨大?
问题现象
在 claude.ai 官方聊天界面中使用 docx skill 转换 Markdown 文档效果非常好,但在 FastAPI + Next.js 的应用环境中调用 Claude API 时,效果却特别差。
根本原因分析
这个问题的本质在于:Skill 不仅仅是提示词,它是「提示词 + 可执行代码 + 运行时环境」的完整组合。
1. claude.ai 环境的特殊能力
在 claude.ai 官方界面中,Claude 具备以下能力:
┌─────────────────────────────────────────────────────────────┐
│ claude.ai 环境 │
├─────────────────────────────────────────────────────────────┤
│ ✓ Computer Use 功能 - 可以执行终端命令 │
│ ✓ Artifacts 功能 - 可以创建和下载文件 │
│ ✓ 代码执行沙箱 - 可以运行 Python/JavaScript │
│ ✓ 完整的文件系统访问 │
│ ✓ 预装的依赖环境(docx、pandoc 等) │
└─────────────────────────────────────────────────────────────┘当你在 claude.ai 中要求转换文档时,Claude 实际上会:
- 读取 Skill 文档了解 docx-js 库的 API
- 生成并执行 JavaScript 代码
- 调用
Packer.toBuffer()生成真正的 .docx 二进制文件 - 通过 Artifacts 提供下载
2. FastAPI + Next.js API 环境的局限
┌─────────────────────────────────────────────────────────────┐
│ FastAPI + Next.js API 环境 │
├─────────────────────────────────────────────────────────────┤
│ ✗ 无代码执行能力 - Claude 只能生成代码文本 │
│ ✗ 无文件系统访问 - 无法创建或操作文件 │
│ ✗ 纯文本输入输出 - 无法处理二进制数据 │
│ ✗ 无运行时环境 - 没有 Node.js/Python 执行器 │
└─────────────────────────────────────────────────────────────┘在 API 调用场景中,Claude 只能:
- 理解你的需求
- 生成转换代码的文本
- 返回代码字符串——但无法执行
这就是为什么"效果差"的真正原因:你得到的只是代码,而不是转换后的文件。
3. 正确的解决方案架构
要在 FastAPI + Next.js 环境中实现类似效果,需要采用以下架构:
┌─────────────────────────────────────────────────────────────┐
│ 推荐的解决方案架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 用户请求 │
│ │ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ Next.js 前端 │ │
│ └────────┬─────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ FastAPI 后端 │──────│ Claude API │ │
│ │ │ │ (内容结构生成) │ │
│ └────────┬─────────┘ └──────────────────┘ │
│ │ │
│ │ Claude 返回结构化内容(JSON/Markdown) │
│ │ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ 文档转换服务 │ ← 使用 python-docx 或 docx-js │
│ │ (后端执行代码) │ │
│ └────────┬─────────┘ │
│ │ │
│ ▼ │
│ .docx 文件输出 │
│ │
└─────────────────────────────────────────────────────────────┘关键点:将 Claude 的角色定位为「内容结构生成器」,而非「文件转换执行器」。
4. 具体实现建议
方案 A:Python 后端实现
# FastAPI 后端示例
from fastapi import FastAPI
from docx import Document
from docx.shared import Inches, Pt
import anthropic
app = FastAPI()
@app.post("/convert-md-to-docx")
async def convert_md_to_docx(markdown_content: str):
# 1. 使用 Claude 解析 Markdown 结构
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-4-20250514",
messages=[{
"role": "user",
"content": f"""将以下 Markdown 解析为结构化 JSON 格式:
{markdown_content}
返回格式:{{"elements": [{{"type": "heading1|paragraph|list", "content": "..."}}]}}"""
}]
)
# 2. 使用 python-docx 创建实际文档
doc = Document()
structure = json.loads(response.content[0].text)
for element in structure["elements"]:
if element["type"] == "heading1":
doc.add_heading(element["content"], level=1)
elif element["type"] == "paragraph":
doc.add_paragraph(element["content"])
# ... 处理其他类型
# 3. 返回文件
doc.save("output.docx")
return FileResponse("output.docx")方案 B:Node.js 中间服务
// 使用 docx-js 库
const { Document, Packer, Paragraph, TextRun } = require('docx');
async function convertMarkdownToDocx(markdownContent, claudeGeneratedStructure) {
const doc = new Document({
sections: [{
children: claudeGeneratedStructure.elements.map(elem => {
if (elem.type === 'paragraph') {
return new Paragraph({
children: [new TextRun(elem.content)]
});
}
// ... 处理其他类型
})
}]
});
return await Packer.toBuffer(doc);
}Skill 概述
目标用途
Claude 官方 DOCX Skill 是一个全面的 Word 文档处理工具包,专门设计用于让 Claude 能够:
| 功能类别 | 具体能力 |
|---|---|
| 创建文档 | 从零开始生成专业格式的 .docx 文件 |
| 编辑文档 | 修改现有 Word 文档的内容和格式 |
| 追踪修改 | 实现法律/商务文档的红线审阅(Redlining) |
| 添加批注 | 在文档中添加评论和回复 |
| 格式保持 | 在编辑过程中保持原有格式不被破坏 |
| 文本提取 | 从 Word 文档中提取纯文本内容 |
核心价值
这个 Skill 解决了一个关键问题:Word 文档(.docx)本质上是 ZIP 压缩包内的 XML 文件集合,直接操作非常复杂。这个 Skill 封装了所有底层细节,让 Claude 可以像专业文档处理软件一样工作。
架构分析
文件结构总览
docx/
├── SKILL.md # 主入口文档,定义工作流程和决策树
├── LICENSE.txt # 许可证文件
├── docx-js.md # JavaScript/TypeScript 文档创建教程
├── ooxml.md # Office Open XML 技术参考和 Python 库文档
├── ooxml/
│ ├── schemas/ # XML Schema 定义文件
│ └── scripts/
│ ├── pack.py # 将目录打包为 .docx 文件
│ ├── unpack.py # 将 .docx 文件解包为目录
│ ├── validate.py # 文档验证脚本
│ └── validation/ # 验证器模块
└── scripts/
├── __init__.py
├── document.py # 核心 Python 库(Document 类)
├── utilities.py # XML 编辑工具(XMLEditor 类)
└── templates/ # XML 模板文件工作流程决策树
┌─────────────────────────────────┐
│ 用户请求处理文档 │
└─────────────────────────────────┘
│
┌───────────────┴───────────────┐
│ 任务类型是什么? │
└───────────────────────────────┘
/ | \
/ | \
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 读取/分析 │ │ 创建新 │ │ 编辑现有 │
└──────────┘ └──────────┘ └──────────┘
│ │ │
▼ ▼ │
┌──────────┐ ┌──────────┐ │
│ pandoc │ │ docx-js │ │
│ 转 MD │ │ (JS/TS) │ │
└──────────┘ └──────────┘ │
│
┌────────────────────────────┤
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ 自己的文档 + │ │ 他人的文档 / 法律 │
│ 简单修改 │ │ / 商务 / 政府文档 │
└─────────────────────┘ └─────────────────────┘
│ │
▼ ▼
┌─────────────────────┐ ┌─────────────────────┐
│ 基础 OOXML 编辑 │ │ 红线审阅工作流 │
│ (Document 类) │ │ (Redlining) │
└─────────────────────┘ └─────────────────────┘核心组件详解
1. SKILL.md - 主入口文档
这是整个 Skill 的"大脑",定义了:
- 工作流程决策树:根据任务类型选择正确的工具
- 文本提取方法:使用 pandoc 转换为 Markdown
- 文档创建流程:指向 docx-js.md
- 文档编辑流程:指向 ooxml.md
- 红线审阅流程:详细的追踪修改实现步骤
关键指令特点:
# 强制性阅读要求
1. **MANDATORY - READ ENTIRE FILE**: Read [`docx-js.md`](docx-js.md) (~500 lines)
completely from start to finish. **NEVER set any range limits when reading this file.**这种设计确保 Claude 在执行任务前完整理解技术细节。
2. docx-js.md - JavaScript 文档创建库
这份约 350 行的技术文档教会 Claude 如何使用 docx npm 包创建 Word 文档。
核心导入
const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell,
ImageRun, Header, Footer, AlignmentType, PageOrientation, LevelFormat,
ExternalHyperlink, InternalHyperlink, TableOfContents, HeadingLevel,
BorderStyle, WidthType, TabStopType, UnderlineType, ShadingType,
VerticalAlign, SymbolRun, PageNumber, FootnoteReferenceRun,
Footnote, PageBreak } = require('docx');关键编码规则
| 规则 | 正确做法 | 错误做法 |
|---|---|---|
| 换行符 | 使用单独的 Paragraph 元素 | 使用 \n 字符 |
| 列表 | 使用 LevelFormat.BULLET 常量 | 使用 Unicode 符号 • |
| 分页符 | new Paragraph({ children: [new PageBreak()] }) | 单独的 new PageBreak() |
| 表格阴影 | ShadingType.CLEAR | ShadingType.SOLID(导致黑色背景) |
| 图片 | 必须指定 type: "png" | 省略 type 参数 |
样式系统
const doc = new Document({
styles: {
default: { document: { run: { font: "Arial", size: 24 } } },
paragraphStyles: [
{ id: "Heading1", name: "Heading 1", basedOn: "Normal",
run: { size: 32, bold: true },
paragraph: { spacing: { before: 240, after: 240 }, outlineLevel: 0 } },
// outlineLevel 对目录功能至关重要
]
}
});3. ooxml.md - Office Open XML 技术参考
约 610 行的深度技术文档,涵盖:
DOCX 文件的本质结构
document.docx (实际是 ZIP 文件)
├── [Content_Types].xml # 内容类型声明
├── _rels/
│ └── .rels # 关系定义
└── word/
├── document.xml # 主文档内容
├── styles.xml # 样式定义
├── settings.xml # 文档设置
├── comments.xml # 批注内容
├── numbering.xml # 列表编号定义
├── media/ # 嵌入的图片等媒体
└── _rels/
└── document.xml.rels # 文档关系XML 元素排序规则
OOXML 有严格的元素顺序要求:
<!-- w:pPr 内的元素必须按此顺序 -->
<w:pPr>
<w:pStyle> <!-- 1. 段落样式 -->
<w:numPr> <!-- 2. 编号属性 -->
<w:spacing> <!-- 3. 间距 -->
<w:ind> <!-- 4. 缩进 -->
<w:jc> <!-- 5. 对齐方式 -->
</w:pPr>追踪修改的 XML 模式
<!-- 插入内容 -->
<w:ins w:id="1" w:author="Claude" w:date="2025-01-15T10: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-15T10:00:00Z">
<w:r><w:delText>deleted text</w:delText></w:r>
</w:del>4. scripts/document.py - 核心 Python 库
这是一个约 1277 行的高级封装库,提供了操作 DOCX 文件的完整 API。
Document 类
from scripts.document import Document
# 初始化(自动创建临时工作目录、设置基础设施)
doc = Document('unpacked_directory')
doc = Document('unpacked_directory', author="John Doe", initials="JD")
doc = Document('unpacked_directory', track_revisions=True)
# 通过下标访问任何 XML 文件
node = doc["word/document.xml"].get_node(tag="w:p", contains="some text")
node = doc["word/comments.xml"].get_node(tag="w:comment", attrs={"w:id": "0"})
# 添加批注
doc.add_comment(start=node1, end=node2, text="这里需要修改")
doc.reply_to_comment(parent_comment_id=0, text="同意这个修改")
# 保存(自动验证)
doc.save()DocxXMLEditor 类
继承自 XMLEditor,添加了自动属性注入功能:
# 自动注入的属性包括:
# - w:rsidR, w:rsidRDefault, w:rsidP (段落和文本运行)
# - w:id, w:author, w:date (追踪修改元素)
# - xml:space="preserve" (含空格的文本)关键方法:
| 方法 | 用途 |
|---|---|
get_node() | 通过标签、属性、行号、文本内容查找节点 |
replace_node() | 替换节点内容 |
insert_after() | 在节点后插入内容 |
insert_before() | 在节点前插入内容 |
suggest_deletion() | 将内容标记为删除(追踪修改) |
revert_insertion() | 拒绝他人的插入 |
revert_deletion() | 拒绝他人的删除 |
追踪修改示例
# 最小化编辑:将 "30 days" 改为 "60 days"
node = doc["word/document.xml"].get_node(tag="w:r", contains="within 30 days")
rpr = tags[0].toxml() if (tags := node.getElementsByTagName("w:rPr")) else ""
replacement = f'''
<w:r w:rsidR="00XYZ789">{rpr}<w:t>within </w:t></w:r>
<w:del><w:r>{rpr}<w:delText>30</w:delText></w:r></w:del>
<w:ins><w:r>{rpr}<w:t>60</w:t></w:r></w:ins>
<w:r w:rsidR="00XYZ789">{rpr}<w:t> days</w:t></w:r>
'''
doc["word/document.xml"].replace_node(node, replacement)5. scripts/utilities.py - XML 编辑工具
约 375 行的底层 XML 操作工具。
XMLEditor 类核心功能
class XMLEditor:
def __init__(self, xml_path):
"""解析 XML 并跟踪每个元素的行号位置"""
def get_node(self, tag, attrs=None, line_number=None, contains=None):
"""多条件节点查找"""
def replace_node(self, elem, new_content):
"""替换节点"""
def insert_after(self, elem, xml_content):
"""节点后插入"""
def save(self):
"""保存修改"""特色功能:行号追踪解析器
def _create_line_tracking_parser():
"""
创建一个 SAX 解析器,为每个元素记录原始行号和列号。
这使得可以通过 Read 工具输出的行号精确定位元素。
"""6. ooxml/scripts/ - 打包解包工具
unpack.py - 解包 DOCX
python ooxml/scripts/unpack.py document.docx ./unpacked功能:
- 将 .docx ZIP 归档解压到目录
- 格式化 XML 文件便于阅读
- 建议使用的 RSID 值
pack.py - 打包 DOCX
python ooxml/scripts/pack.py ./unpacked output.docx功能:
- 将目录重新打包为 .docx 文件
- 可选的 Schema 验证
红线审阅(Redlining)工作流
这是这个 Skill 最复杂也最有价值的功能,专为法律、商务、政府文档设计。
完整流程
1. 获取 Markdown 表示
└─> pandoc --track-changes=all input.docx -o current.md
2. 识别并分组修改
└─> 按章节、类型或复杂度分批(每批 3-10 个修改)
3. 读取文档并解包
└─> python ooxml/scripts/unpack.py input.docx ./unpacked
4. 分批实现修改
└─> 创建 Python 脚本使用 Document 类
└─> 测试每批修改后再继续
5. 打包文档
└─> python ooxml/scripts/pack.py ./unpacked reviewed.docx
6. 最终验证
└─> pandoc --track-changes=all reviewed.docx -o verification.md
└─> 检查所有修改是否正确应用修改原则:最小化、精确
# 错误做法 - 替换整句
'<w:del><w:delText>The term is 30 days.</w:delText></w:del>'
'<w:ins><w:t>The term is 60 days.</w:t></w:ins>'
# 正确做法 - 只标记变化的部分
'<w:r><w:t>The term is </w:t></w:r>'
'<w:del><w:r><w:delText>30</w:delText></w:r></w:del>'
'<w:ins><w:r><w:t>60</w:t></w:r></w:ins>'
'<w:r><w:t> days.</w:t></w:r>'依赖项
| 工具 | 安装命令 | 用途 |
|---|---|---|
| pandoc | sudo apt-get install pandoc | 文本提取和格式转换 |
| docx (npm) | npm install -g docx | JavaScript 创建新文档 |
| defusedxml | pip install defusedxml | 安全的 XML 解析 |
| LibreOffice | sudo apt-get install libreoffice | PDF 转换 |
| Poppler | sudo apt-get install poppler-utils | PDF 转图片 |
设计亮点总结
- 分层架构:高级 Python API → 底层 XML 操作 → 原始文件打包
- 自动化基础设施:Document 类自动处理 RSID、命名空间、关系文件
- 验证机制:Schema 验证 + 红线验证确保文档完整性
- 渐进式学习:SKILL.md 作为入口,按需深入具体技术文档
- 防错设计:详尽的"错误做法 vs 正确做法"对比示例
在自定义应用中的最佳实践
如果你希望在 FastAPI + Next.js 应用中实现类似功能,建议:
- 将 Claude 用于内容生成,而非文件操作
- 在后端实现文件转换逻辑(使用 python-docx 或 docx-js)
- 定义清晰的 JSON 中间格式作为 Claude 输出和后端转换之间的桥梁
- 参考这个 Skill 的 docx-js.md 学习正确的 docx 库用法
- 考虑使用 pandoc 作为通用文档转换器
# 推荐的 FastAPI 服务架构
@app.post("/generate-docx")
async def generate_docx(content_request: ContentRequest):
# Step 1: Claude 生成结构化内容
structure = await claude.generate_document_structure(content_request)
# Step 2: 后端执行实际转换
docx_bytes = document_service.create_docx(structure)
# Step 3: 返回文件
return Response(
content=docx_bytes,
media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document"
)这样可以充分利用 Claude 的语言理解能力,同时规避 API 调用环境无法执行代码的限制。