Word 文档
DOCX 创建、编辑与分析
.docx 文件本质上是一个包含 XML 文件的 ZIP 压缩包。请根据任务选择相应方法:
| 任务 | 方法 |
|---|---|
| 创建新文档 | 编写 docx (npm) 脚本 —— 详见下文注意事项 |
| 编辑现有文档 | unzip $\rightarrow$ 编辑 word/document.xml $\rightarrow$ zip (docx-js 无法打开现有文件) |
| 读取内容 | pandoc -t markdown file.docx |
> 以下脚本路径均相对于本技能目录。
使用 docx-js 创建 —— 注意事项
docx 已预装 —— 请勿先运行 npm install;直接编写脚本并 require('docx')。仅在 require 失败时才执行 npm install docx。模型熟悉该 API,但请注意以下易错点:
- 页面尺寸默认为 A4。 如需 US Letter 尺寸,请设置
page: { size: { width: 12240, height: 15840 } }(单位为 DXA;1440 = 1″)。
- 横向页面: 传入纵向尺寸并设置
orientation: PageOrientation.LANDSCAPE—— docx-js 内部会自动交换宽和高。
- 表格需要双重宽度设置: 需在表格上设置
columnWidths且在每个单元格上设置width,且两者均使用WidthType.DXA(使用PERCENTAGE在 Google Docs 中会失效)。列宽之和必须等于表格总宽。
- 表格底纹: 使用
ShadingType.CLEAR,切勿使用SOLID(否则会渲染为黑色)。
- 列表: 切勿直接插入
•字符;请使用配置了LevelFormat.BULLET的numbering。
ImageRun必须指定type:(如"png","jpg"等)。
PageBreak必须位于Paragraph内部。
- 切勿使用
\n—— 请使用独立的Paragraph元素。
- 目录 (TOC): 标题必须使用内置的
HeadingLevel.*;自定义标题样式需设置outlineLevel,否则不会出现在目录中。
- 不要用表格代替水平线 —— 请使用段落底边框。
- 引导点 / 同行右对齐: 在
TextRun中使用PositionalTab(alignment: PositionalTabAlignment.RIGHT,leader: PositionalTabLeader.DOT),而非直接输入.或空格填充。
验证输出
写入 .docx 后,请将其渲染并查看:
python scripts/office/soffice.py --headless --convert-to pdf output.docx
pdftoppm -jpeg -r 100 output.pdf page
ls page-*.jpg # 然后读取图像pdftoppm 会根据页数对页码进行补零(例如 page-01.jpg…page-12.jpg)。
编辑现有文档
旧版 .doc 文件必须先转换:python scripts/office/soffice.py --headless --convert-to docx file.doc。
unzip -q doc.docx -d unpacked/
find unpacked -type l -delete # 删除符号链接 —— 外部来源的 docx 不可信
python scripts/merge_runs.py unpacked/ # 合并碎片化的 run,以便于查找文本
直接编辑 unpacked/word/document.xml —— 切勿重新格式化或美化打印 (pretty-print)
(cd unpacked && rm -f ../out.docx && zip -Xr ../out.docx .)
python scripts/office/validate.py out.docx --original doc.docx # XSD 检查;--auto-repair 可修复常见问题
需要修订记录?添加 --author "<修订人姓名>" 以检查每项编辑是否被追踪
Word 会将文本拆分到多个 <w:r> run 中(由于修订 ID、拼写检查标记等),因此你在文档中看到的短语在 XML 中通常不是连续的字符串。merge_runs.py 会在不改变内容或渲染效果的情况下,合并 word/document.xml 中格式相同的相邻 run;它也支持直接处理 .docx 文件 (python scripts/merge_runs.py doc.docx -o merged.docx)。
修订追踪: 在进行修订时,请使用 --author "<修订人姓名>" 进行验证(需配合 --original) —— 它会报告任何未包含在 <w:ins>/<w:del> 中的文本更改。
这很容易在无意中发生,且在“接受修订”的视图中不可见。使用带有 w:id、w:author 和 w:date 属性的 <w:ins>/<w:del> 标签包裹 run。在 <w:del> 内部,文本元素应为 <w:delText> 而非 <w:t>。被删除的段落标记(<w:pPr><w:rPr><w:del w:id=".." w:author=".." w:date=".."/></w:rPr></w:pPr>)意味着“将此段落合并到下一段”——因此,完全删除一个段落需要该标记加上包裹每个 run 的 <w:del>。<w:del/> 必须位于 rPr 其他子元素之前,因为其顺序受 schema 强制约束。
若要生成一份接受所有修订的干净副本,请运行:python scripts/accept_changes.py in.docx out.docx。
接受被删除的段落标记应将该段落与下方段落合并,因此如果一个段落的所有 run 都被删除了,该段落应随之消失。Word 可以实现这一点,但 accept_changes.py 和 pandoc --track-changes=accept 并不总是如此。两者的失败方式相同——它们删除了被删除的文本,但留下了空的段落,如果该段落之前是自动编号的,则会显示为一个多余的空项目符号:
pandoc --track-changes=accept从不合并段落。
accept_changes.py(LibreOffice) 可以正确合并,除非被删除的段落后面跟着一个空的间隔段落。
在任何视图中出现的空项目符号都是该视图的渲染产物,而非文档缺陷。请在 XML 中检查段落删除情况。
批注 (Comments)
批注需要六个相互关联的文件。请使用辅助脚本——如果你同时在编辑 document.xml,请使用目录模式(可节省解压/重新压缩的周期),否则使用 .docx 直接模式:
# 针对已解压的目录(在放置标记时推荐使用)
python scripts/comment.py unpacked/ "Fees & expenses cap is too low"
python scripts/comment.py unpacked/ "Agreed" --parent 0
直接针对 .docx 文件
python scripts/comment.py contract.docx "This cap is too low" -o annotated.docx该脚本会写入 comments.xml、commentsExtended.xml、commentsIds.xml、commentsExtensible.xml、关系文件以及内容类型覆盖文件。批注 ID 是自动分配的。随后,它会打印出 <w:commentRangeStart>/<w:commentRangeEnd>/<w:commentReference> 代码片段,以便将其添加到 word/document.xml 中,使批注锚定到特定文本——在放置这些标记之前,批注虽然存在但不可见。
依赖项
docx (npm, 预装 —— 仅在 require('docx') 失败时安装) · pandoc · LibreOffice (soffice) · pdftoppm (Poppler)