统一文档模型:14 种格式如何归一为一套 Markdown
Word 是 XML 包,PPT 是另一套 XML 包,Excel 又不一样,RTF 是纯文本控制字,PDF 是页面描述语言,EPUB 是打包的网页……14 种格式,14 套内部结构。要把它们都变成同一种 Markdown,最直白的思路是:为每种格式写一个"专属转换器"。但这条路会很快塌掉。
逐格式硬编码的坑
设想你为 .docx 写了一堆规则:找 w:body、解析 w:p、处理 w:tbl……再为 .pptx 另写一套,为 .xlsx 又一套。问题立刻来了:
- 维护爆炸:14 种格式 × 各自的边界情况,代码量呈指数增长。
- 表现不一致:同一份"二级标题",在 Word 和 PowerPoint 里可能转出来长得不一样。
- 新增即重写:每支持一种格式,几乎要从头再来。
Everything to Markdown 借鉴的开源模型,用的是另一条更优雅的路:先归一,再输出。
两步走:解析 → 序列化
整条管线分两个阶段,中间夹着一个关键的东西——统一文档模型。
原始文件 ──(解析器 A/B/C…)──▶ 统一文档模型 ──(序列化器)──▶ Markdown
.docx 各自不同 一份结构化表示 唯一一套规则
.pptx ────────┘
.xlsx ────────┘
第一步:解析进同一个模型
每种格式有自己的解析器,但它们的输出目标一致:都填进同一个"文档模型"。这个模型只关心语义,不关心来源:
- 有标题,以及它的层级(h1/h2/h3…)
- 有段落、列表(有序/无序/嵌套)
- 有表格(含合并单元格)
- 有强调(粗体/斜体)、链接、图片
- 有脚注、引用等元信息
于是 .docx 的 w:pStyle w:val="Heading2",和 .pptx 里某个被判定为标题的文本框,在模型里都只是"一个二级标题"。来源的差异,在第一步就被消化掉了。
第二步:一套序列化器打天下
因为模型是统一的,输出 Markdown 时只需要一套规则:标题怎么写、列表怎么写、表格怎么写。无论资料来自 2003 年的老 .doc 还是昨天下载的 .pptx,出来的 Markdown 风格完全一致。
这就像把英语、法语、日语都先翻译成"世界语",再从世界语译成一门目标语言——中间那步统一了,后面就简单了。
为什么这件事很重要
对使用者而言,统一模型带来的直接好处是可预测:你不用记"Word 转出来长这样、Excel 转出来长那样"。同一套逻辑处理所有格式,意味着:
- 一个格式的 bug 修复,往往惠及所有格式;
- 新格式接入时,只需写"如何填进模型",不用碰输出逻辑;
- AI 拿到的 Markdown 始终是同一种"方言",更容易稳定消费。
小结
"先归一,再输出"是 Everything to Markdown 能把 14 种格式都转好的底层原因。下一篇,我们反过来问一个更接地气的问题:在解析之前,程序怎么知道手里的文件到底是哪种格式?