ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Word 文档公式转换详解:以 Docling 的 equations.docx.md 基准文件剖析 OMML 到 LaTeX 的实现

Word 文档公式转换详解:以 Docling 的 equations.docx.md 基准文件剖析 OMML 到 LaTeX 的实现 Word 文档公式转换详解以 Docling 的 equations.docx.md 基准文件剖析 OMML 到 LaTeX 的实现【免费下载链接】doclingGet your documents ready for gen AI项目地址: https://gitcode.com/GitHub_Trending/do/doclingDocling 将 Word.docx文档转换为结构化 DoclingDocument 与 Markdown 时数学公式的处理是一条独立的实现链路Word 内部用 OMMLOffice Math Markup Language存储公式Docling 将其逐元素转换为 LaTeX再按“行内公式 / 独立公式”两种形态嵌入正文。本文以转换基准文件tests/data/docx/groundtruth/equations.docx.md为主体完整解析它所覆盖的公式形态、Docling 的转换输出结构Markdown、DoclingDocument JSON、层级树并深入源码说明 OMML→LaTeX 的实现与测试验证方式。读完后你将能够读懂该基准文件的每一段内容对应哪种公式场景、定位公式转换在 docling/backend/msword_backend.py 与 docling/backend/docx/latex/omml.py 中的实现位置、并知道如何运行相关测试验证转换结果。基准文件是什么一次 Word 公式文档转换的期望输出equations.docx.md 是 Docling 测试数据目录中的一份 groundtruth基准输出。它与以下三个文件构成同一文档的四种视图文件作用equations.docx转换输入源Word 文档公式以 OMML 形式存储equations.docx.md期望的 Markdown 输出本文主体equations.docx.json期望的 DoclingDocument JSON 结构equations.docx.itxt期望的文档层级树item 列表表示端对端转换测试会将源文档实际转换出的 Markdown 与该基准文件逐字比对因此这份文件本身就是“公式转换能力”的可执行验收标准。下面先完整给出基准文件内容再逐类解析其覆盖的公式场景。This is a word document and this is an inline equation: $A \pi r^{2}$ . - First item with inline equation: $A \pi r^{2}$ is the area formula. - Second item with equations: $Emc^{2}$ and $Fma$ are physics formulas. - The formula $a^{2}b^{2}c^{2}$ is the Pythagorean theorem. If instead, I want an equation by line, I can do this: $$a^{2}b^{2}c^{2} \times 23$$ And that is an equation by itself. Cheers! This is another equation: $$f\left(x\right)a_{0}\sum_{n1}^{ \infty }\left(a_{n}\cos(\frac{n \pi x}{L})b_{n}\sin(\frac{n \pi x}{L})\right)$$ This is text. This is text. ...(连续重复的填充段落) This is a word document and this is an inline equation: $A \pi r^{2}$ . If instead, I want an equation by line, I can do this: $$\left(xa\right)^{n}\sum_{k0}^{n}\left(\genfrac{}{}{0pt}{}{n}{k}\right)x^{k}a^{n-k}$$ And that is an equation by itself. Cheers! This is another equation: $$\left(1x\right)^{n}1\frac{nx}{1!}\frac{n\left(n-1\right)x^{2}}{2!} \text{ \textellipsis }$$ This is text. ...(连续重复的填充段落) This is a word document and these are inline equations: $N_{s}^{H}$ / $N_{s}^{P}$ ​. If instead, I want an equation by line, I can do this: $$e^{x}1\frac{x}{1!}\frac{x^{2}}{2!}\frac{x^{3}}{3!} \text{ \textellipsis } , - \infty x \infty$$ And that is an equation by itself. Cheers! Large operators and integrals are represented with n-ary objects in OMML XML: $$\sum_{0}^{2}x$$ $$\bigcup_{n1}^{m}\left(X_{n} \cap Y_{n}\right)$$ $$\prod_{k1}^{n}A_{k}$$ $$\bigwedge_{}^{}x$$ $$\int_{}^{}(2x1)dx$$ $$\iint_{0}^{1}xdx$$ $$\iiint_{}^{}ydy$$ $$\oint_{}^{}\frac{dy}{dx}$$ $$\oiint_{0}^{2 \pi }idt$$ $$\oiiint_{C}^{}\frac{1}{z}dz$$ Operators used with limits: $$\operatorname{argmax}_{ \epsilon}f(x), \lim_{n}{\left(1\frac{1}{n}\right)}^{n} , \max_{0 \leq x \leq 1}xe^{-x^{2}}, unsupported_{n}{\left(1\frac{1}{n}\right)}^{n}$$ Equations with the OMML group character object: $$P_{ x}\underbrace{S \cdot T \cdot G \cdot (xyz)}_{group\ with\ underbraces}e^{x}$$ $$Q_{ y}\overset{group\ with\ overbraces}{\overbrace{G \cdot T \cdot S \cdot (xyz)}}e^{y}$$ $$s\left\{max\right\} A \times B$$逐类解析这份基准文件覆盖了哪些公式场景基准文件并非随意堆砌公式而是按 OMML 的构造类型逐段组织每一段对应转换链路中的一个关键能力点。行内公式inline equation第一段正文与随后三个列表项展示的是“文字与公式混排”场景普通段落中的行内公式This is a word document and this is an inline equation: $A \pi r^{2}$ .列表项中的行内公式三条-列表项分别覆盖“单公式”“同一列表项内两个公式$Emc^{2}$与$Fma$“公式夹在文字中间”三种情况。同一列表项内公式与文本交替出现如第二项中Second item with equations: $Emc^{2}$ and $Fma$ are physics formulas.公式之间还夹着普通文本and。值得注意的是第三处混排段落$N_{s}^{H}$ / $N_{s}^{P}$​中两个行内公式之间用斜杠分隔且第二个公式后保留了一个零宽字符基准文件第 31 行这是对“公式紧贴标点/不可见字符”这类边角输入的输出保真验证——转换结果不能吞掉也不能错误改写这些字符。独立公式display equation独立成行的公式在 Markdown 输出中统一使用$$...$$包裹。基准文件包含多组带乘积尾项的简单式$$a^{2}b^{2}c^{2} \times 23$$傅里叶级数求和、上下限、无穷大、分数嵌套$$f\left(x\right)a_{0}\sum_{n1}^{ \infty }\left(a_{n}\cos(\frac{n \pi x}{L})b_{n}\sin(\frac{n \pi x}{L})\right)$$二项式定理其中组合数被转换为\genfrac{}{}{0pt}{}{n}{k}形式说明 Docling 对 OMML 中的 binomial 构造有专门映射展开式中的\text{ \textellipsis }即省略号经 OMML 的 text 对象转出为 LaTeX 的\textellipsis每个$$公式段落前后都有空的 text 段落占位见基准文件第 7、10 行的空段这一点在 equations.docx.itxt 的层级树中可以一一对应后文展开。n-ary 大算子与积分基准文件中“Large operators and integrals are represented with n-ary objects in OMML XML”一节集中列出了 10 个 n-ary 构造$$\sum_{0}^{2}x$$ $$\bigcup_{n1}^{m}\left(X_{n} \cap Y_{n}\right)$$ $$\prod_{k1}^{n}A_{k}$$ $$\bigwedge_{}^{}x$$ $$\int_{}^{}(2x1)dx$$ $$\iint_{0}^{1}xdx$$ $$\iiint_{}^{}ydy$$ $$\oint_{}^{}\frac{dy}{dx}$$ $$\oiint_{0}^{2 \pi }idt$$ $$\oiiint_{C}^{}\frac{1}{z}dz$$覆盖了求和、并集、连乘、逻辑与、单/双/三重积分、闭环积分、双/三重闭环积分并且包含上、下界留空\int_{}^{}的情况验证转换器对空 limits 的降级输出不会报错。带极限的算子与“unsupported”回退Operators used with limits一节的单行公式同时包含四种算子$$\operatorname{argmax}_{ \epsilon}f(x), \lim_{n}{\left(1\frac{1}{n}\right)}^{n} , \max_{0 \leq x \leq 1}xe^{-x^{2}}, unsupported_{n}{\left(1\frac{1}{n}\right)}^{n}$$前三个argmax、lim、max是算子与下标极限组合的标准写法第四个unsupported_{n}{...}是故意使用的未知算子名——从源码结构看docling/backend/docx/latex/latex_dict.py 中定义了 LIM_FUNC极限类函数、FUNC函数类等算子映射表已知算子会被赋予极限排版而unsupported这类不在映射表中的名字走原样输出的回退路径。把这两种行为放进同一个公式可以在一条断言里同时验证“正确映射”与“未知算子不崩溃”。OMML group 字符对象与特殊字符结尾两节覆盖更细的构造$$P_{ x}\underbrace{S \cdot T \cdot G \cdot (xyz)}_{group\ with\ underbraces}e^{x}$$ $$Q_{ y}\overset{group\ with\ overbraces}{\overbrace{G \cdot T \cdot S \cdot (xyz)}}e^{y}$$ $$s\left\{max\right\} A \times B$$前两个分别是\underbrace与\overset{...}{\overbrace{...}}的花括号分组构造第三个\left\{max\right\}验证反斜杠转义字符在花括号中的输出。源码链路OMML 是如何变成这些 LaTeX 的基准文件里每一行$$与$都来自同一条转换链路核心代码集中在两个文件。OMML→LaTeX 转换器docling/backend/docx/latex/omml.pydocling/backend/docx/latex/omml.py约 864 行的模块 docstring 说明了它的职责将 Word 文档中的 OMML 元素转换为 LaTeX 格式处理分数、上下标、矩阵、极限与特殊字符文件头部还注明其实现改编自开源的 dwml 项目2025-01-23 引入。几个可直接观察到的实现事实模块以OMML_NS {http://schemas.openxmlformats.org/officeDocument/2006/math}作为 OMML 命名空间常量所有 lxml 元素查找都基于该命名空间大量转换规则以字典常量形式放在 docling/backend/docx/latex/latex_dict.pyLIM_FUNC、FUNC、GROUPING_FUNCS、RAD、POS、MATH_CHARS等omml.py 顶部一次性导入——基准文件中lim/max/argmax与unsupported的不同输出正是查这张表的结果模块对pylatexenc.latexencode.UnicodeToLatexEncoder做了带保护的可选导入try: import ... except ImportError: pass并注释说明该依赖由MsWordDocumentBackend.__init__统一保证用于把公式中的 Unicode 数学字符编码为 LaTeX。段落内公式混排msword_backend.py 的 _handle_equations_in_textdocling/backend/msword_backend.py 是 .docx 后端主体约 3794 行公式相关的关键方法_handle_equations_in_text约 L1925遍历段落元素把普通文本片段与公式分别收集公式以带标记的形式eq.../eq进入only_equations列表并插入原文本的对应位置返回(output_text, only_equations)。方法内有一道防护若解析得到的公式/文本子串与原段文本无法对齐数量或内容不一致会记录日志并放弃公式解析、原样返回原段落文本——宁可输出纯文本也不输出错位的公式。这正是基准文件中混排段落能逐字比对的前提。_add_inline_equations_to_parent约 L2410把“文本 行内公式”作为子项挂到父元素下注释明确说明它同时服务于普通段落与列表项两条路径_add_list_item_with_equations约 L2639专门处理含行内公式的列表项与_handle_text_elements中“若列表项检测到len(equations) 0则走特殊分支”的调用点对应——这就是基准文件三条-列表项在输出中仍保留列表语义、且公式以$...$嵌在项内文字中间的原因。表格单元格内同样会调用_handle_equations_in_text约 L2793-L2797表格公式的覆盖由table_with_equations.docx姊妹样本单独验证见文末扩展阅读。输出结构印证JSON 与层级树里的 FormulaItem基准 Markdown 只是同一转换结果的投影结构化的真相在 equations.docx.json 与 equations.docx.itxt 中。DoclingDocument JSON该 JSON 顶部声明{ schema_name: DoclingDocument, version: 1.10.0, name: equations, origin: { mimetype: application/vnd.openxmlformats-officedocument.wordprocessingml.document, binary_hash: 14529667209329784536, filename: equations.docx }, ... }origin记录了输入文件类型与内容哈希body.children通过$ref如#/groups/0、#/texts/17引用正文元素。含行内公式的段落在结构中呈现为 groupinline 容器挂多个子项text 与 formula 交替独立公式段落则直接作为顶层 formula 元素出现在 body 子项序列中。层级树 .itxt 的逐项对应equations.docx.itxt 用缩进树呈现了同一结构例如基准文件开头的混排段落在树中是item-0 at level 0: unspecified: group _root_ item-1 at level 1: inline: group group item-2 at level 2: text: This is a word document and this is an inline equation: item-3 at level 2: formula: A \pi r^{2} item-4 at level 2: text: . item-5 at level 1: list: group list item-6 at level 2: list_item: item-7 at level 3: inline: group group item-8 at level 4: text: First item with inline equation: item-9 at level 4: formula: A \pi r^{2} item-10 at level 4: text: is the area formula.可以清楚看到含公式的段落被包装为inline: group其下text与formula子项交替排列列表项为list - list_item - inline: group的三层嵌套。独立公式则直接挂在一级如item-25 at level 1: formula: a^{2}b^{2}c^{2} \times 23。另外.itxt 对超长公式行会做省略显示如f\left(x\right)a_{0}\sum_{n1} ... })...一行这是树视图的展示截断完整公式仍以 JSON 与 Markdown 输出为准。验证与复现如何确认这份基准仍然成立端到端测试比对tests/test_backend_msword.py 中的test_e2e_docx_conversionsL100 是核心验收用例它对tests/data/docx/sources/下的 docx 样本执行转换并将生成的 Markdown 与groundtruth/目录中同名.md基准逐一比对——equations.docx在其中。公式输出的任何一个字符变化例如\bigwedge写成\bigwedge_{}^{}x的变体都会使该测试失败。公式混排逻辑的单元测试同一测试文件中还有针对混排解析的定向用例test_handle_equations_in_text_returns_original_text_on_mismatchL1022当解析子串与原段文本不匹配时方法必须返回原始文本、equations为空test_handle_equations_in_text_skips_empty_substringsL1039空子串应被跳过而公式仍被收录test_handle_text_elements_inline_equations_stop_when_text_is_consumedL1110文本被公式标记消费完毕后循环应正确终止。在仓库根目录下安装好开发依赖后运行pytest tests/test_backend_msword.py -k equations即可只跑与公式相关的用例跑全文件则覆盖列表、表格、代码块、页眉页脚等其他 docx 场景同一文件约 1642 行、50 个测试函数。手动复现转换结果不想跑测试时可以直接对源文档做转换并查看输出docling convert tests/data/docx/sources/equations.docx或使用 Python API参考 docs/examples/minimal.py 的最简用法from docling.document_converter import DocumentConverter converter DocumentConverter() result converter.convert(tests/data/docx/sources/equations.docx) print(result.document.export_to_markdown())把打印出的 Markdown 与 equations.docx.md 对照即可手工验证本文解析的全部公式形态调用result.document的 JSON 导出则可对照 equations.docx.json 检查 FormulaItem 的层级。相关公式样本这套机制的更宽覆盖tests/data/docx/下还有一组聚焦 OMML 细节的姊妹样本与equations.docx共同构成公式转换的完整测试面样本sources 目录下针对的 OMML 场景omml_frac_superscript.docx分数与上下标组合构造omml_func_log.docx函数类算子log 等映射omml_multi_equation_paragraph.docx同一自然段内多段公式omml_text_escapes_in_math.docx公式内 text 对象的转义字符table_with_equations.docx表格单元格内的公式对应 msword_backend.py 的单元格分支每个样本同样配有.md/.json/.itxt三种 groundtruth验证方式与本文完全一致。小结equations.docx.md这份看似简单的基准文件实际是 Docling “Word 公式 → LaTeX/Markdown” 转换能力的浓缩验收清单行内与独立公式、n-ary 大算子与积分、极限算子及未知算子回退、花括号分组与特殊字符全部以可逐字断言的形式固定下来。其背后的实现分两层——omml.py 负责 OMML 元素到 LaTeX 字符串的元素级翻译映射表在 latex_dict.pymsword_backend.py 负责把翻译结果按段落、列表项、表格单元格的上下文安全地装配回文档结构并在文本对齐失败时降级为纯文本输出。理解了这一文件与这条链路你就掌握了在 Docling 中排查任何 docx 公式转换问题的完整路径先看基准文件确定期望行为再沿_handle_equations_in_text与 omml 转换器定位偏差。【免费下载链接】doclingGet your documents ready for gen AI项目地址: https://gitcode.com/GitHub_Trending/do/docling创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表