← 提示词库 Meta/muse-agent/skills/artifacts/document/references/editing.md 原文 md
🌐 中英双语对照

Editing existing Word documents / 编辑现有 Word 文档

A .docx (and a .dotx template, handled identically) is a ZIP archive of
XML parts. Route by what the edit needs:

.docx(以及 .dotx 模板,处理方式相同)是一个由 XML 部件组成的 ZIP 归档。按编辑所需选择路径:

Edit Path
Content changes on a doc you generated Revise the .src/ generator and regenerate
Simple content changes on an uploaded doc Open it with python-docx, edit, save
Tracked changes (redlines), comments, format-preserving surgical edits Raw XML: unpack, edit word/document.xml, repack (python-docx cannot express these)
Read or extract content muse.read opens a .docx directly (converted to markdown, paged); iterate with python-docx when you need structure the markdown flattens
Legacy .doc Convert first: soffice --headless --convert-to docx file.doc, then treat as above
编辑类型 路径
对你生成的文档做内容修改 修改 .src/ 生成器并重新生成
对上传文档做简单内容修改 用 python-docx 打开、编辑、保存
修订(红线批注)、批注、保持格式的精细修改 原始 XML:解包、编辑 word/document.xml、重新打包(python-docx 无法表达这些操作)
读取或提取内容 muse.read 直接打开 .docx(转换为 markdown 并分页);当需要被 markdown 展平的结构时,用 python-docx 迭代
旧版 .doc 先转换:soffice --headless --convert-to docx file.doc,然后按上述方式处理

The raw-XML round trip / 原始 XML 往返

unzip -q doc.docx -d unpacked/
find unpacked -type l -delete   # ZIP entries from outside parties can be symlinks; strip before touching the tree
# edit unpacked/word/document.xml IN PLACE
(cd unpacked && rm -f ../out.docx && zip -Xr ../out.docx .)

Run fragmentation / 文本运行碎片化

Word splits visible text across many <w:r> runs (revision ids,
spell-check markers, editing history), so a phrase you can read in the
document often does not exist as a contiguous string in the XML, and a
find-and-replace silently misses. Before string edits, coalesce adjacent
runs whose <w:rPr> serialize byte-identically (both absent also
matches); that criterion provably leaves rendering unchanged. rsid*
attributes and <w:proofErr> elements are pure metadata and safe to
strip. Never merge across two different <w:ins>/<w:del> wrappers:
that rewrites tracked-change structure and collapses separate revisions.

Word 会把可见文本拆散到许多 <w:r> 运行(run)中(修订 ID、拼写检查标记、编辑历史),因此你在文档中能读到的短语在 XML 中往往不是连续字符串,查找替换会悄悄漏掉。在做字符串编辑之前,先把 <w:rPr> 序列化后字节相同的相邻运行合并(两者都缺失也算匹配);该准则可以证明不会改变渲染。rsid* 属性和 <w:proofErr> 元素是纯元数据,可以安全去除。绝不要跨越两个不同的 <w:ins>/<w:del> 包装合并:那会改写修订结构并把不同修订折叠到一起。

Tracked changes (redlining) / 修订(红线批注)

Wrap changed runs in <w:ins>/<w:del>, each carrying w:id,
w:author, and w:date.

把被修改的运行包进 <w:ins>/<w:del>,每个都带有 w:id、w:author 和 w:date。

To hand back a clean all-accepted copy, drive headless LibreOffice with a
StarBasic macro dispatching .uno:AcceptAllTrackedChanges, then verify by
unpacking the output and grepping that no w:ins/w:del remain. Two
gotchas: soffice can hang after storing (a timeout is not a failure;
verify the output content instead of the exit), and a fully-deleted
paragraph followed by an empty spacer paragraph can survive as an emptied
paragraph, showing up as a stray empty bullet when auto-numbered. That
bullet is an artifact of the accepted view; judge paragraph deletions in
the XML.

要交回一份接受全部修订的干净副本,用 StarBasic 宏驱动无头 LibreOffice 派发 .uno:AcceptAllTrackedChanges,然后通过解包输出并 grep 确认没有残留 w:ins/w:del 来验证。两个坑:soffice 可能在存储后挂起(超时不是失败;要验证输出内容而不是退出码);一个被完全删除的段落后面跟着一个空的间隔段落时,可能以清空段落的形式残留,在自动编号时表现为一个多余的空项目符号。该项目符号是接受视图的产物;段落删除要在 XML 中判断。

Comments / 批注

Comments span six cross-linked locations: word/comments.xml,
word/commentsExtended.xml, word/commentsIds.xml,
word/commentsExtensible.xml, their four Relationship entries in
word/_rels/document.xml.rels, and four Override entries in
[Content_Types].xml. The ID chain: w:comment carries w:id and a
paragraph w14:paraId; commentsExtended keys on that paraId;
commentsIds maps paraId to a durableId; commentsExtensible keys on the
durableId.

批注横跨六个相互链接的位置:word/comments.xml、word/commentsExtended.xml、word/commentsIds.xml、word/commentsExtensible.xml、它们在 word/_rels/document.xml.rels 中的四个 Relationship 条目,以及 [Content_Types].xml 中的四个 Override 条目。ID 链:w:comment 携带 w:id 和段落 w14:paraId;commentsExtended 以该 paraId 为键;commentsIds 把 paraId 映射到 durableId;commentsExtensible 以 durableId 为键。

Verify / 验证

Every edit ends with the render gate in
/opt/hatch/skills/artifacts/testing/SKILL.md: convert to PDF with headless
LibreOffice, rasterize with pdftoppm, and read every page image before
returning a link.

每次编辑都以 /opt/hatch/skills/artifacts/testing/SKILL.md 中的渲染闸门收尾:用无头 LibreOffice 转换为 PDF,用 pdftoppm 栅格化,并在返回链接之前查看每一页图像。