
文档开发工具CLI【免费下载链接】pandocUniversal markup converter项目地址https://gitcode.com/gh_mirrors/pa/pandoc点击查看免费下载导读本文以 pandoc 仓库中的命令测试用例 test/command/6959.md 为切入点完整还原并解读 pandoc 如何处理 MS Word 的修订Track Changes功能——包括插入、删除与批注comment三类标记的往返round-trip流程。你将掌握--track-changesaccept|reject|all三档语义、批注在 markdown 中对应的comment-start/comment-endspan 语法以及从 docx 读取到写出 docx 的完整源码级调用链可直接运用于文档审校、批注归档与自动化审稿脚本的编写。一、测试用例docx 批注的完整往返1.1 用例内容test/command/6959.md 全文是一个典型的 pandoc 命令测试golden test脚本通过一个三步管道验证批注信息能否无损穿透格式转换% pandoc -t docx -o - | pandoc -f docx -t markdown --track-changesall [This is the comment]{.comment-start id1 authorMike date2020-12-17T16:53:00Z} [Here is my reply]{.comment-start id2 authorMike date2020-12-17T17:39:00Z} This is the content being commented on [[]{.comment-end id2}]{.comment-end id1} ^D [This is the comment]{.comment-start id1 authorMike date2020-12-17T16:53:00Z} [Here is my reply]{.comment-start id2 authorMike date2020-12-17T17:39:00Z} This is the content being commented on [[]{.comment-end id2}]{.comment-end id1}第一行%开头是执行命令先将 markdown 输入转换为 docx 输出到标准输出-o -再由--track-changesall模式读取该 docx 并转回 markdown输入与输出以^DEOF分隔二者完全一致说明 pandoc 的 docx 读写器对批注数据实现了无损往返。该用例的关键验证点是嵌套批注结构批注id1内部嵌套了批注id2且文本 This is the content being commented on 同时被两个批注覆盖元数据保留作者authorMike与时间戳date2020-12-17T16:53:00Z在往返后原样保留ID 归属正确comment-end以[]{.comment-end id2}与[]{.comment-end id1}的顺序闭合保证嵌套关系不串位。1.2 运行验证方式在仓库根目录执行下面的命令即可复现该用例需要有 pandoc 可执行文件或cabal run pandoc/stack run pandoc构建后运行printf %s\n [This is the comment]{.comment-start id1 authorMike date2020-12-17T16:53:00Z} [Here is my reply]{.comment-start id2 authorMike date2020-12-17T17:39:00Z} This is the content being commented on [[]{.comment-end id2}]{.comment-end id1} | pandoc -t docx -o - | pandoc -f docx -t markdown --track-changesall若输出与输入一致即证明往返成功。该用例同时被 pandoc 的命令测试框架test/Tests/Command.hs 驱动的 golden test 体系纳入回归测试用于防止 docx 读写器后续改动破坏批注往返的兼容性。二、--track-changes三档语义详解2.1 命令行参数定义src/Text/Pandoc/App/CommandLineOptions.hs 中定义了该选项的解析逻辑option [track-changes] (ReqArg (\arg opt - do action - case arg of accept - return AcceptChanges reject - return RejectChanges all - return AllChanges _ - optError $ PandocOptionError $ T.pack Argument of --track-changes must be accept, reject, or all return opt { optTrackChanges action }) accept|reject|all) (Fixed [accept,reject,all]) (T.pack Handling of Word track-changes)可见参数取值严格限定为accept、reject、all三者之一其它取值会直接报错Argument of --track-changes must be accept, reject, or all。2.2 内部数据类型src/Text/Pandoc/Options.hs 定义了对应的代数数据类型data TrackChanges AcceptChanges | RejectChanges | AllChanges deriving (Show, Read, Eq, Data, Typeable, Generic)该类型同时实现了FromJSON/ToJSON实例src/Text/Pandoc/Options.hs意味着它不仅能通过命令行设置也能通过 YAML/JSON 格式的默认选项文件配置且 JSON 键名采用accept-changes、reject-changes、all-changes形式同时兼容短写法accept、reject、all。2.3 三档语义依据 MANUAL 与源码MANUAL.txt 对三档语义的权威说明如下accept默认值处理所有插入insertion和删除deletion修订——插入内容被采纳进正文删除内容被移除reject忽略所有插入和删除修订——插入内容被丢弃删除内容恢复all保留所有插入、删除与批注并分别包装为带有insertion、deletion、comment-start、comment-end类的 span同时携带修订的作者与时间信息。关键点accept与reject都会忽略批注comments只有all会保留批注。这正是 6959 号用例必须使用--track-changesall的原因。此外 MANUAL 还指出all模式的脚本化价值只接受某位审阅者的改动或某日期之前的改动——即先用all保留全部标记信息再通过 Lua 过滤器或自写脚本按author/date属性筛选。若整段段落被插入或删除all模式还会在被影响的段落断行前生成paragraph-insertion/paragraph-deletion类 span。该选项仅影响 docx 读取器。三、源码级实现docx 读取器如何还原批注3.1 批注 span 的生成src/Text/Pandoc/Readers/Docx.hs 中parPartToInlines函数处理批注开始与结束标记parPartToInlines (CommentStart cmtId author date bodyParts) do opts - asks docxOptions case readerTrackChanges opts of AllChanges - do blks - smushBlocks $ mapM bodyPartToBlocks bodyParts ils - blocksToInlinesWarn cmtId blks let attr (, [comment-start], (id, cmtId) : addAuthorAndDate author date) return $ spanWith attr ils _ - return mempty parPartToInlines (CommentEnd cmtId) do opts - asks docxOptions case readerTrackChanges opts of AllChanges - do let attr (, [comment-end], [(id, cmtId)]) return $ spanWith attr mempty _ - return mempty从源码结构可以推断出以下实现事实开关决定一切只有readerTrackChanges AllChanges时批注才被保留其它两档直接返回空内联memp ty与 MANUAL 描述一致span 语法映射CommentStart生成Span (, [comment-start], (id, cmtId) : author/date 属性)即 markdown 中的[批注文本]{.comment-start id... author... date...}CommentEnd生成空内容、仅带id属性的comment-endspan即[]{.comment-end id...}作者与日期通过addAuthorAndDate合并进 span 属性对应测试用例中的authorMike date2020-12-17T16:53:00Z。插入、删除修订在相邻代码段src/Text/Pandoc/Readers/Docx.hs中处理AcceptChanges时插入被采纳、删除被丢弃RejectChanges时反之AllChanges时则分别包装为insertion/deletionspan。3.2 底层 docx 解析批注标记w:commentRangeStart/w:commentRangeEnd与修订标记w:ins/w:del的 XML 解析位于 src/Text/Pandoc/Readers/Docx/Parse.hs解析结果以CommentStart、CommentEnd、ChangedRuns等数据结构进入上层Docx.hs的转换逻辑。整个 docx 读取链路为docx (zipxml) → Parse.hs 解析 body/段落/注释 → bodyPartToBlocks/parPartToInlines → (readerTrackChanges 分支) → markdown span四、源码级实现docx 写出器如何还原批注4.1 批注 span 的写出src/Text/Pandoc/Writers/Docx/OpenXML.hs 中inlineToOpenXML处理两类批注 spaninlineToOpenXML _ (Span (ident,[comment-start],kvs) ils) do -- prefer the id in kvs, since that is the one produced by the docx reader. let ident fromMaybe ident (lookup id kvs) kvs filter ((id /) . fst) kvs modify $ \st - st{ stComments ((id,ident):kvs, ils) : stComments st } return [ Elem $ mknode w:commentRangeStart [(w:id, ident)] () ] inlineToOpenXML opts (Span (ident,[comment-end],kvs) content) do let ident fromMaybe ident (lookup id kvs) nestedContent - inlinesToOpenXML opts content let thisCommentEnd [ mknode w:commentRangeEnd [(w:id, ident)] () , mknode w:r [] [ mknode w:rPr [] [ mknode w:rStyle [(w:val, CommentReference)] () ] , mknode w:commentReference [(w:id, ident)] () ] ] return $ map Elem thisCommentEnd nestedContent实现要点ID 解析优先读取 span 属性中的iddocx 读取器产生的正是这种形式否则回退到 span 的 identifier 字段comment-start把 span 内容登记进内部状态stComments供后续生成批注内容区并输出w:commentRangeStart元素标记批注起点comment-end输出w:commentRangeEnd闭合范围再生成带CommentReference字符样式的w:commentReference引用标记注释中还特别提到处理嵌套内容nestedContent是为了修复 #8189 号嵌套批注问题——与 6959 号用例的嵌套场景相互印证。因此 6959 号用例中从 markdown span 到 docx 再回到 markdown span 的往返实际经历了markdown spancomment-start/comment-end → OpenXML.hsw:commentRangeStart / w:commentRangeEnd / w:commentReference → Parse.hs Docx.hsCommentStart / CommentEnd → 相同结构的 markdown span五、与其他修订相关选项的配合5.1--strip-comments命令行解析中紧随--track-changes之后定义了--strip-comments[true|false]src/Text/Pandoc/App/CommandLineOptions.hs用于剥离 docx 中的注释内容两者可组合使用例如用--track-changesall保留修订标记、再用--strip-comments去除纯批注文本。5.2 通过选项文件配置由于TrackChanges实现了 JSON 序列化见上文在默认选项文件中可写作track-changes: all等效于命令行--track-changesallMANUAL 中的选项对照表MANUAL.txt也给出了--track-changes accept↔track-changes: accept的对应关系。5.3 实际工作流建议审稿归档pandoc input.docx -t markdown --track-changesall输出保留全部修订与批注的 markdown便于版本管理git diff 友好仅接受特定审阅者先以all导出再写 Lua 过滤器按Span的author属性筛除不符合条件的insertion/deletionspan正式定稿pandoc input.docx -t markdown默认accept直接得到已采纳所有修订的干净文本。六、总结6959 号测试用例完整展示了 pandoc 对 Word 批注的无损往返能力docx 读取器在AllChanges模式下将批注转换为comment-start/comment-endspan 并保留id、author、date元数据docx 写出器再将这些 span 还原为w:commentRangeStart、w:commentRangeEnd与w:commentReference等 OOXML 元素。掌握--track-changes三档语义及其 span 语法即可在文档审校、批注抽取、自动化审稿等场景中灵活运用 pandoc 的修订处理能力。赞分享文档开发工具CLI【免费下载链接】pandocUniversal markup converter项目地址https://gitcode.com/gh_mirrors/pa/pandoc点击查看免费下载相关推荐pandoc 转换带 Word 修订标记的 docx 时如何设置 --track-changespandoc 转换带 Word 修订标记的 docx 时如何设置 track changes 如果你用 pandoc 转换由 Word 生成的 .docx 文文档开发工具CLIdocx 修订追踪Track Changes完整指南用 InsertedTextRun、DeletedTextRun 与 revision 属性生成带修订标记的 Word 文档docx 修订追踪Track Changes完整指南用 InsertedTextRun、DeletedTextRun 与 revision 属性生成带修订文档OfficeCLI Word 修订Track ChangesAPI 全攻略从标记创建到 accept/reject 的端到端实践OfficeCLI Word 修订Track ChangesAPI 全攻略从标记创建到 accept/reject 的端到端实践 导读 本文基于 Offi人工智能AI 应用AI 技能CLIMCP 服务上一篇go-elasticsearch大规模数据处理如何应对亿级文档索引下一篇ResMLP模型resmlp_36_224.fb_distilled_in1k常见问题排查与解决方案终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考