Word 文档
.docx 创建、编辑、读取及视觉验证
docx 技能默认可用,当您提到 Word 文档、.docx 文件、报告、备忘录、信函或模板时会自动触发。无需手动加载。概述
docx 技能涵盖 Word 文档的完整生命周期:从零创建、编辑现有文件、读取与分析、基于模板生成、修订管理,以及强制性视觉 QA 验证。该技能仅适用于 .docx 文件 — 不包括 PDF、电子表格、HWPX 或 Google Docs。
主要工具是 officecli,一个位于 PATH 上的命令行工具,可处理约 80% 的任务(add、set、remove、validate、query、track-change accept/reject)。对于 officecli 无法处理的任务 — 修订的创建、OMML 公式、批量模式匹配 — 该技能会回退到 scripts/ 中的 Python OOXML 脚本。
触发条件
| 模式 | 示例 |
|---|---|
| 文件扩展名 | .docx、Word 文档 |
| 文档类型 | 报告、备忘录、信函、提案、合同 |
| 关键词 | "Word doc"、"template"、"tracked changes"、"table of contents" |
| 韩语触发词 | "워드 문서"、"보고서 만들어줘"、"문서 작성해줘" |
快速参考
| 任务 | 工具 | 命令模式 | 备注 |
|---|---|---|---|
| 按现有文档格式化 | shell + officecli | cp source.docx target.docx && officecli open target.docx | 继承样式/页眉/页脚 |
| 创建空白 DOCX | officecli | officecli create report.docx | 从真实 Office 文件开始 |
| 添加段落 | officecli | officecli add FILE /body --type paragraph --prop text="..." | 主要写入路径 |
| 编辑段落/运行 | officecli | officecli set FILE /body/p[N] --prop ... | 精确路径定位 |
| 读取文本/大纲/统计 | officecli | officecli view FILE text | 模式:text、annotated、outline、stats、issues、html |
| 查询文档 | officecli | officecli query FILE "p[style=Heading1]" | 类 CSS 选择器 |
| 模板替换 | officecli | officecli set FILE / --prop find="{{X}}" --prop replace="Y" | 保留模板结构 |
| 验证/问题扫描 | officecli | officecli validate FILE | 配合 view FILE issues 使用 |
| 接受/拒绝修订 | officecli | officecli set FILE / --prop accept-changes=all | 也支持 reject-changes=all |
| 创建修订 | Python (L3/L4) | scripts/docx_cli.py + ooxml/redline_diff.py | officecli 无法创建 — 只能接受/拒绝 |
| OMML 公式 | Python (L4) | 解压 → 注入 <m:oMath> → 重新打包 | officecli 无法生成 OMML |
| 复杂锚定批注 | Python (L3) | python3 scripts/comment.py IN OUT --text "..." --anchor "..." | 用于超出 officecli 能力的批注 |
| PDF 转换/视觉 QA | soffice | soffice --headless --convert-to pdf FILE | 基于截图的 QA |
"~해줘" 用法示例
从零创建季度报告文档,包含正确的标题层级、目录、表格和专业排版。使用
officecli create → 添加结构 → 验证 → PDF 确认。
基于参考文件编辑:复制源文件以继承所有样式、页眉和页脚,然后替换正文内容同时保留文档的视觉标识。请参阅下方的"基于参考文件编辑"工作流。
使用
officecli view FILE text 和 view FILE outline 读取并分析文档,然后提供标题、关键内容和文档统计信息的结构化摘要。
通过 Python OOXML 脚本创建修订(红线标记),因为 officecli 只能接受/拒绝修订而无法创建修订。会自动升级到 L3/L4。
使用
officecli set FILE / --prop find="{{X}}" --prop replace="Y" 进行模板安全替换,在保留模板格式和结构的同时填充占位符。
基于参考文件编辑
当用户说"按照 X.docx 的格式"、"匹配现有样式"、"基于模板",或提供源文件时 — 始终从源文件开始。切勿从零重建。
工作流
- 复制源文件:
cp source.docx target.docx— 继承所有样式、边距、编号、页眉、页脚 - 打开:
officecli open target.docx— 守护进程启动;命令立即返回 - 仅删除正文内容 — 保留
/styles、/numbering、/header、/footer - 使用现有样式名称添加新段落(例如
--prop style=Heading1)— 样式会自动应用
为什么这很重要
Pandoc 生成的和 Word 生成的文档具有特定的样式 ID(例如 Heading1、BodyText、FirstParagraph),这些 ID 对该文档来说是唯一的。添加同名的新样式会导致:
officecli validate报告重复样式 ID 错误- Word/LibreOffice 渲染回退到默认设置
- 任务耗时增加 10 倍
模板优先级
- 用户提供的源文件 — 一等模板
tests/fixtures/*.docx— 技能自带的预构建工作示例officecli create空白文件 — 仅在无其他选择时使用
# 正确做法:继承 Pandoc 样式
cp Assignment1.docx Assignment2.docx
officecli open Assignment2.docx
officecli remove Assignment2.docx "/body/p[1]" # 删除旧正文(保留样式/页眉/页脚)
# ... 删除更多段落 ...
officecli add Assignment2.docx /body --type paragraph --prop text="New title" --prop style=Heading1
officecli close Assignment2.docx
# 错误做法:重新创建已存在的样式 -- validate 会失败
officecli add doc.docx /styles --type style --prop name=Heading1 --prop size=20pt ...
升级阶梯
当 officecli 无法完成任务时,按以下顺序升级:
| 级别 | 何时使用 | 工具 |
|---|---|---|
| L1 officecli 高层级 | 典型的 add/set/remove 操作 | officecli add/set/remove/query/view |
| L2 officecli raw-set | XML 注入 — PAGE 字段、fldChar、超链接锚点、自定义属性 | officecli raw-set FILE PATH --xpath X --action A --xml ... |
| L3 Python 脚本 | 批量修订操作、添加批注、合并 run、红线验证 | python3 scripts/*.py |
| L4 解压 → 编辑 XML → 重新打包 | OMML 公式、自定义样式注入、模式匹配编辑 | scripts/docx_cli.py open FILE work/ → 编辑 XML → scripts/docx_cli.py save work/ OUT.docx |
升级信号
- officecli 显示 "silently ignored" → L2 (raw-set)
- 需要 OMML/MathML 公式 → L4(注入
<m:oMath>XML) - 需要创建修订(officecli 只能接受/拒绝)→ L3 或 L4
- 批量查找/替换超过 100 个目标 → L3(
docx_cli.py search/replace) - Pandoc 生成的文档包含自定义样式 ID → 先使用"基于参考文件编辑"
- 任务在 L1+L2 后仍然失败 → 在放弃之前阅读相关的
references/*.md
核心工作流
执行模型
逐条执行命令。不要将所有命令写入 shell 脚本并作为单个块执行。OfficeCLI 是增量式的:每个 add、set 和 remove 都会立即修改文件并返回输出。
- 逐条执行命令,然后查看输出。在继续之前检查退出码。
- 非零退出码 = 立即停止并修复。不要在损坏状态上继续构建。
- 在结构性操作后进行验证。添加样式、表格、图表或节之后,先运行
get或validate再在其上继续构建。
读取与分析
officecli view doc.docx text # 完整文本提取
officecli view doc.docx text --max-lines 200 # 截断提取
officecli view doc.docx text --start 1 --end 50 # 范围提取
officecli view doc.docx outline # 结构:统计、标题、页眉/页脚
officecli view doc.docx annotated # 每个 run 的样式/字体/大小,公式显示为 LaTeX
officecli view doc.docx stats # 段落数、样式/字体分布
元素检查
officecli get doc.docx / # 文档根节点(元数据、页面设置)
officecli get doc.docx /body --depth 1 # 列出正文子元素
officecli get doc.docx "/body/p[1]" # 指定段落
officecli get doc.docx "/body/p[1]/r[1]" # 指定 run
officecli get doc.docx "/body/tbl[1]" --depth 3 # 表格结构
officecli get doc.docx /styles # 样式定义
officecli get doc.docx "/styles/Heading1" # 指定样式
officecli get doc.docx "/header[1]" # 页眉/页脚
officecli get doc.docx /numbering # 编号定义
officecli get doc.docx "/body/p[1]" --json # 用于脚本的 JSON 输出
类 CSS 查询
officecli query doc.docx 'paragraph[style=Heading1]' # 按样式
officecli query doc.docx 'p:contains("quarterly")' # 按文本内容
officecli query doc.docx 'p:empty' # 空段落
officecli query doc.docx 'image:no-alt' # 无替代文本的图片
officecli query doc.docx 'p[align=center] > r[bold=true]' # 复合选择器
officecli query doc.docx 'paragraph[size>=24pt]' # 按大小
officecli query doc.docx 'field[fieldType!=page]' # 按类型筛选字段
页眉与页脚
add --type footer 命令中 --prop field=page 会被静默忽略。页脚只会创建静态文本。您必须在创建页脚后使用 raw-set 注入 PAGE 字段。# 步骤 1:为封面页创建空页脚(自动启用 differentFirstPage)
officecli add doc.docx / --type footer --prop type=first --prop text=""
# 步骤 2:带有静态 "Page " 文本的默认页脚
officecli add doc.docx / --type footer --prop text="Page " \
--prop type=default --prop align=center --prop size=9pt --prop font=Calibri
# 步骤 3:通过 raw-set 注入 PAGE 字段
# (footer[2] = 当首页页脚也存在时的默认页脚)
officecli raw-set doc.docx "/footer[2]" \
--xpath "//w:p" \
--action append \
--xml '<w:r ...><w:fldChar w:fldCharType="begin"/></w:r>
<w:r ...><w:instrText xml:space="preserve"> PAGE </w:instrText></w:r>
<w:r ...><w:fldChar w:fldCharType="end"/></w:r>'
页脚索引规则:当同时添加了首页页脚和默认页脚时,默认页脚是 /footer[2]。如果没有首页页脚,默认页脚是 /footer[1]。始终使用 officecli get doc.docx "/footer[2]" 进行验证。
驻留模式(性能优化)
始终使用 open/close — 这是明智的默认做法。每条命令都无需重复文件 I/O。
officecli open doc.docx # 一次性加载到内存(立即返回)
officecli add doc.docx ... # 所有命令在内存中运行 -- 速度快
officecli set doc.docx ...
officecli close doc.docx # 一次性写入磁盘
officecli open 作为后台 shell 任务运行(例如通过 run_in_background)。它会立即返回,守护进程自动在后台运行。将其作为受监控的 shell 运行会产生僵尸进程和文件锁。批处理模式
在单个 open/save 周期内执行多个操作:
cat <<'EOF' | officecli batch doc.docx
[
{"command":"add","parent":"/body","type":"paragraph",
"props":{"text":"Introduction","style":"Heading1"}},
{"command":"add","parent":"/body","type":"paragraph",
"props":{"text":"This report covers Q4 results.","font":"Calibri","size":"11pt"}}
]
EOF
批处理支持:add、set、get、query、remove、move、swap、view、raw、raw-set、validate。
子技能参考
更多细节存放在按需加载的伴随文件中:
| 子技能 | 使用场景 |
|---|---|
| officecli-academic-paper | 学术论文、引用、参考文献、论文目录 |
| creating.md | 详细的创建方法(从零创建新文档) |
| editing.md | 详细的编辑指南(修改现有文档) |
决策流程
文档是否为学术论文(毕业论文、期刊、会议论文)?
是 --> 阅读 officecli-academic-paper/SKILL.md
否 --> 继续使用主技能
用户是否提供了要匹配的源文件?
是 --> 基于参考文件编辑 + editing.md
否 --> creating.md
Python OOXML 脚本
当 officecli 达到其极限时,该技能会回退到以下 Python 脚本:
| 脚本 | 用途 | 命令 |
|---|---|---|
scripts/docx_cli.py | 统一 Python CLI — 解压、保存、验证、修复、搜索、目录、分块、批注、接受修订、合并 run | python3 scripts/docx_cli.py {open|save|validate|repair|text|search|...} |
scripts/accept_changes.py | 接受所有修订 | python3 scripts/accept_changes.py IN.docx OUT.docx |
scripts/comment.py | 添加符合 W3C 规范的 OOXML 批注并锚定到文本 | python3 scripts/comment.py IN.docx OUT.docx --text "..." --anchor "..." |
scripts/ooxml/merge_runs.py | 合并格式相同的相邻 run | python3 scripts/ooxml/merge_runs.py unpacked/ |
scripts/ooxml/redline_diff.py | 验证修订与原始文档的正确性 | python3 scripts/ooxml/redline_diff.py unpacked/ original.docx |
scripts/ooxml/simplify_tracked.py | 简化同一作者的相邻修订 | python3 scripts/ooxml/simplify_tracked.py unpacked/ |
参考材料
| 文件 | 何时阅读 | 包含内容 |
|---|---|---|
references/cjk-handling.md | 韩文文本/东亚字体/换行问题 | rFonts 东亚字体、lang 标签、无障碍性 |
references/tracked-changes.md | 修订/批注/红线标记工作 | w:ins、w:del、批注 XML、脚本使用示例 |
商务文档设计原则
标题层级
- H1:文档标题(每篇文档一个)
- H2:主要章节
- H3:H2 下的子章节
- 切勿跳级(H1 → H3 无效)。目录依赖正确的标题结构。
# 验证标题层级
officecli view report.docx outline
配色方案
| 用途 | 允许的颜色 | 十六进制示例 |
|---|---|---|
| 标题、强调 | 海军蓝 | #003366、#1B2A4A |
| 正文装饰、边框 | 炭灰色 | #333333、#4A4A4A |
| 高亮、标注 | 森林绿 | #2E5E3F、#1A4731 |
切勿在单个文档中使用彩虹色、亮原色或超过 3 种强调色。
字体选择
| 文字类型 | 主要字体 | 备用字体 |
|---|---|---|
| 韩文 | Malgun Gothic | Pretendard |
| 英文/拉丁文 | Calibri | Aptos |
排版规范
正文:11-12pt。标题递增:H1 = 最小 18pt(长文档推荐 20pt),H2 = 14pt 加粗,H3 = 12pt 加粗。正文行距 1.15x-1.5x。
内容到元素的映射
| 内容类型 | 推荐元素 | 原因 |
|---|---|---|
| 顺序项目 | 无序列表(listStyle=bullet) | 比行内逗号分隔更易浏览 |
| 逐步流程 | 有序列表(listStyle=numbered) | 数字传达顺序 |
| 对比数据 | 带表头行的表格 | 列式布局便于并排比较 |
| 趋势数据 | 嵌入图表(chartType=line/column) | 视觉化模式识别 |
| 关键定义 | 悬挂缩进段落 | 将术语与定义分离 |
| 法律/合同条款 | 带书签的有序列表 | 通过书签进行交叉引用 |
| 数学内容 | 公式元素(formula=LaTeX) | 正确的 OMML 渲染 |
| 引用/参考 | 脚注或尾注 | 保持正文简洁 |
| 引述/标注 | 带边框和底纹的段落 | 与正文形成视觉区分 |
| 多节布局 | 分节符与分栏 | 按节控制分栏 |
强制性验证
# 步骤 1:结构验证
officecli validate output.docx
# 步骤 2:视觉 PDF 验证
soffice --headless --convert-to pdf --outdir /tmp output.docx
# 打开/检查 PDF 以确认:格式、表格、图片、页眉/页脚
- 跳过 PDF 验证 = 未经验证的输出
- 如果
validate报告错误,在交付文件之前修复它们
QA 检查清单
假设存在问题。你的工作就是找到它们。
问题检测
officecli view doc.docx issues
officecli view doc.docx issues --type format
officecli view doc.docx issues --type content
officecli view doc.docx issues --type structure
内容 QA
officecli view doc.docx text
officecli view doc.docx outline
officecli query doc.docx 'p:empty'
officecli query doc.docx 'image:no-alt'
# 检查残留占位符
officecli query doc.docx 'p:contains("lorem")'
officecli query doc.docx 'p:contains("placeholder")'
交付前检查清单
- 已设置元数据(标题、作者)
- 通过
raw-set在页脚中注入了 PAGE 字段 — 使用officecli get doc.docx "/footer[2]" --depth 3验证 - 如果文档有封面页,已添加首页页脚
- 封面页内容至少填满页面的 60%
- 当文档有 3 个以上标题时包含目录
- 最后一页内容至少填满页面的 40%
- 标题层级正确(无跳级)
- 未使用空段落作为间距
- 所有图片都有替代文本
- 表格有表头行
- 文档通过
officecli validate验证 - 无残留占位符文本
验证循环
- 生成文档
- 运行
view issues+view outline+view text+validate - 列出发现的问题(如果没有,更严格地再查一遍)
- 修复问题
- 重新验证 — 一个修复往往会产生另一个问题
- 重复直到完整的一轮检查没有发现新问题
在至少完成一个"修复-验证"循环之前,不要宣布成功。
常见陷阱
| 陷阱 | 正确做法 |
|---|---|
--name "foo" | 使用 --prop name="foo" — 所有属性都通过 --prop 传递 |
| 猜测属性名称 | 运行 officecli help docx set paragraph --json 获取准确名称 |
shell 字符串中的 \n | 在 --prop text="line1\\nline2" 中使用 \\n 表示换行 |
带 # 的十六进制颜色 | 使用 FF0000 而非 #FF0000 — 无井号前缀 |
| 路径从 1 开始 | /body/p[1]、/body/tbl[1] — XPath 惯例 |
--index 从 0 开始 | --index 0 = 第一个位置 — 数组惯例 |
zsh/bash 中未加引号的 [N] | Shell 会对 /body/p[1] 进行通配符展开 — 始终给路径加引号:"/body/p[1]" |
| 用空段落做间距 | 在段落上使用 spaceBefore/spaceAfter 属性 |
--prop text= 中的 $ | 使用单引号:--prop text='$50M' |
页脚中的 --prop field=page | 被静默忽略。必须使用 raw-set 注入 <w:fldChar> |
| 从模板重建样式 | 先 cp source.docx target.docx — 不要添加已有 ID 的样式 |
将 officecli open 作为后台 shell | 在前台运行 — open 立即返回,守护进程自动在后台运行 |
| 批处理 JSON 解析错误 | 使用 heredoc:cat <<'EOF' | officecli batch FILE.docx |
| 创建 OMML 公式 | officecli 无法生成 OMML — 升级到 L4 |
在 run 上使用 listStyle | listStyle 是段落属性,不是 run 属性 |
| 行级 bold/color/shd | 行的 set 仅支持 height、header 和 c1/c2/c3 文本快捷方式 — 使用单元格级 set |
| 节与根属性名称混淆 | 节使用 pagewidth/pageheight(小写)。文档根使用 pageWidth/pageHeight(驼峰式) |
| 错误的边框格式 | 使用 style;size;color;space 格式:single;4;FF0000;1 |
| 通过空格缩进代码块 | 使用 ind.left 段落属性(例如 --prop ind.left=720) |
LibreOffice 中的 chartType=pie/doughnut | 扇区在 PDF 中不可见 — 改用 column 或 bar |
已知问题
| 问题 | 解决方法 |
|---|---|
| 无视觉预览 | 与 pptx(SVG/HTML)不同,docx 没有内置渲染。使用 view text/outline/annotated/issues 进行验证。在 Word 中打开进行视觉检查。 |
| 创建修订需要原始 XML | OfficeCLI 可以接受/拒绝但无法创建修订。使用 raw-set 或 Python 脚本 (L3)。 |
| 制表位可能需要原始 XML | 制表位创建未在高级命令中暴露。使用 raw-set。 |
| 创建后无法添加图表系列 | set --prop data= 只能更新现有系列。删除并重建图表。 |
| 复杂编号定义 | listStyle=bullet/numbered 涵盖简单情况。多级列表请使用 numId/numLevel。 |
| 批处理间歇性失败 | 约每 15 次批处理操作中有 1 次可能失败。重试或 close/reopen 文件。将大批量拆分为 10-15 个块。 |
| 表格级 padding 产生无效 XML | 不要使用 set tbl[N] --prop padding=N。使用单元格级 padding.top/padding.bottom。 |
| 不支持内部超链接 | hyperlink 只接受绝对 URI。使用 raw-set 配合 <w:hyperlink w:anchor="...">。 |
表格 --index 定位不可靠 | 在 add /body --type table 上的 --index N 可能被忽略。按所需顺序添加内容。 |
view text 所有编号项都显示 "1." | 仅为显示限制。Word/LibreOffice 中渲染的输出显示正确编号。 |
反模式(必须避免)
- 占位数据:输出中切勿留下 "Acme Corp"、"Alice Chen"、"Lorem ipsum"。如果用户未提供数据,询问用户。
- 页脚 PAGE 字段:通过
raw-set设置页码时,XML 结构必须准确(fldChar/instrText/fldChar 序列)。 - 用空段落做间距:使用
spacing-after属性。 - 手动项目符号字符(-、*):使用
listStyle=bullet或listStyle=number。 - 手动字体 XML 注入:当
--prop font=...足够时使用它。 - 忽略参考材料:如果 officecli 无法完成复杂任务,在放弃之前阅读
references/*.md并检查scripts/*.py。 - 重建现有样式:当用户提供源文件时,复制并修改 — 不要从零重建样式。
工具发现
在猜测之前始终从帮助中确认语法:
officecli --help
officecli help docx
officecli help docx add
officecli help docx set
officecli help docx query
officecli help docx add paragraph --json
officecli help docx set run --json
依赖项
| 工具 | 用途 | 状态 |
|---|---|---|
officecli (PATH) | 主要 DOCX CLI — 全局安装包含 CJK 分支 | 必需 |
dotnet | officecli 的运行时/构建 | 分支构建时必需 |
python3 | 回退脚本(scripts/*.py) | L3/L4 时必需 |
lxml | scripts/ooxml/* 的 Python XML 处理 | L3/L4 时必需 |
soffice | PDF 转换/.doc 迁移/宏工作流 | 可选回退 |
pdftoppm | PDF 渲染后的基于图像的 QA | 可选回退 |
前置条件检查
# 必需
python3 -c "import docx, lxml" || echo "MISSING: pip install python-docx lxml"
# 按需:LibreOffice
which soffice >/dev/null 2>&1 || echo "INFO: LibreOffice not installed"
# 按需:OfficeCLI
which officecli >/dev/null 2>&1 || echo "INFO: OfficeCLI not installed"