news 2026/9/5 20:37:00

Docling 序列化体系详解:从 DoclingDocument 多格式导出到自定义 Serializer

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Docling 序列化体系详解:从 DoclingDocument 多格式导出到自定义 Serializer

Docling 序列化体系详解:从 DoclingDocument 多格式导出到自定义 Serializer

【免费下载链接】doclingGet your documents ready for gen AI项目地址: https://gitcode.com/GitHub_Trending/do/docling

Docling(Get your documents ready for gen AI)在完成 PDF、DOCX 等文档解析后,会产出统一的结构化中间表示DoclingDocument。而如何把这份中间表示落回 Markdown、HTML、DocTags、JSON 等文本形态,则由一套独立的序列化(serialization)抽象承担。本文基于仓库文档 docs/concepts/serialization.md 及其配套示例 docs/examples/serialization.ipynb,系统讲解 Docling 序列化器的抽象层次、DoclingDocument导出方法、各格式对表格跨单元格(span)的处理差异,以及如何配置和编写自定义 serializer,帮助你在 RAG、批量转换、文档入库等场景中精确控制导出结果。

1. 序列化抽象:从文档级到组件级

Docling 把「把文档变成文本」这件事拆成了三层抽象:

  1. 文档序列化器(document serializer):以一个DoclingDocument实例初始化,负责产出整篇文档的文本表示(textual representation)。这是最常用的入口;
  2. 组件序列化器(component serializers):面向文档的子构件,例如text serializertable serializerpicture serializerlist serializerinline serializer等。文档级序列化器内部会按组件类型委派给对应的组件序列化器;
  3. 序列化器提供者(serializer provider):进一步把「序列化策略」与「文档实例」解耦的包装层,便于下游应用统一替换序列化行为。

这一分层直接决定了后文的两个能力:你可以只替换某一种组件(比如把 Markdown 输出的表格换成 triplet 形式),也可以整体替换文档级序列化器,而不必触碰转换管线本身。

2. 基类体系与 serialize() 契约

为了兼顾下游应用的灵活性与开箱即用的便利,Docling 定义了一组序列化类层次(实现位于 docling-core 依赖包中,本仓库 pyproject.toml 声明其版本约束为docling-core>=2.91.0,<3.0.0):

  • 各抽象的基类:BaseDocSerializerBaseTextSerializerBaseTableSerializer等组件基类,以及BaseSerializerProvider
  • 上述基类之外的具体实现子类,例如MarkdownDocSerializerHTMLDocSerializer

从客户端视角看,最核心的契约是BaseDocSerializer.serialize():它返回该文档的文本表示,同时附带哪些文档组件实际参与(贡献)了这次序列化的元数据。这一点在做导出审计或调试「某段文本为什么没出现」时非常有用——你可以通过序列化结果中的 span 来源信息定位到具体组件。

3.DoclingDocument的导出方法:序列化器的用户级快捷方式

Docling 预置了 Markdown、HTML、DocTags 等序列化器,并在DoclingDocument上以导出方法的形式直接暴露。文档说明得很明确:像export_to_markdown()这样的导出方法本质上是用户快捷方式(user shorthands),其内部就是直接实例化并委派给相应的 serializer。

在当前仓库中,可以观察到以下导出方法的真实使用分布(对docling/tests/下 Python 代码的统计):

导出方法使用频次(仓库内)典型场景
export_to_markdown()138 次绝大多数示例、CLI、测试的默认输出
export_to_indented_text()16 次纯文本/缩进结构输出(.itxt 地面真值校验)
export_to_dict()9 次稳定 schema 的结构化导出
export_to_html()4 次保留表格 rowspan/colspan 等结构
export_to_doclang()/export_to_doctags()各 2 / 1 次Doclang 文本、DocTags 训练格式

例如 docs/examples/batch_convert.py 展示了批量转换时按目标格式分发导出:YAML 落地export_to_dict()结果、.doctags文件用export_to_doctags()、Markdown 则同时演示了export_to_markdown()export_to_markdown(strict_text=True)两种形态;docs/examples/custom_convert.py 也以同样方式把 JSON、Markdown、DocTags 三种导出写入独立文件。而 docling/datamodel/document.py 在需要「保证稳定 schema」的场景下显式使用export_to_dict()做文档序列化,注释写明了其动机——这正是选择 dict 导出而非文本导出的一个代表性理由。

DoclingDocument本体(及其全部export_to_*方法)定义在 docling-core 包中,本仓库通过 docling/datamodel/document.py 重新导出DoclingDocument等类型,方便用户统一从docling.datamodel.document引用。

4. 格式特定行为:表格单元格跨行跨列(span)如何处理

这是文档中最重要的「格式权衡」章节。Docling 的内部表格模型(TableData.grid)为每个单元格保留了完整的 span 元数据:row_spancol_spanstart_row_offset_idxstart_col_offset_idx。不同输出格式对这些元数据的渲染策略如下(完整继承自原文档):

格式Span 处理
JSON保留。完整的TableData模型无损序列化,包含全部 span 字段。
Doclang保留。表格通过 OTSL 序列化,使用显式续格 token:跨列用LCEL、跨行用UCEL、两者兼有则XCEL
DocTags保留。表格经 OTSL 序列化,OTSL 天然编码 span 结构。
HTML保留。单元格直接输出原生rowspan/colspan属性。
Markdown拍平(Flattened)。Markdown 表格没有 span 语法,序列化器只在原点位置写入单元格文本,span 覆盖的其他网格位置渲染为空单元格。
LaTeX拍平tabular环境暂不输出\multirow/\multicolumn命令。
WebVTT不适用。WebVTT 是字幕/说明格式,表格不会被序列化。

实践结论:如果下游流程依赖准确的表格结构(例如合并的表头单元格),应优先使用export_to_html()export_to_dict(),而不是export_to_markdown()。当然,如果你确实需要 Markdown 中承载跨格信息,也可以子类化BaseTableSerializer实现自定义逻辑,并在实例化文档序列化器时传入(见第 7 节的配置示例,table_serializer参数正是为这种替换设计的)。

5. 实战一:直接应用预置 Serializer

以下代码整理自 docs/examples/serialization.ipynb,演示「转换 + 序列化」的完整闭环。先转换得到DoclingDocument,再对其施加任意BaseDocSerializer

from docling.document_converter import DocumentConverter DOC_SOURCE = "https://arxiv.org/pdf/2311.18481" converter = DocumentConverter() doc = converter.convert(source=DOC_SOURCE).document

HTML 序列化——表格会以<table>结构输出(span 完整保留),图片以<figure>/<figcaption>呈现:

from docling_core.transforms.serializer.html import HTMLDocSerializer serializer = HTMLDocSerializer(doc=doc) ser_result = serializer.serialize() ser_text = ser_result.text # 序列化结果同时携带组件贡献元数据

Markdown 序列化——表格转为标准管道表格(span 被拍平),图片按MarkdownParams配置输出占位符(默认<!-- image -->)或引用/嵌入形式:

from docling_core.transforms.serializer.markdown import MarkdownDocSerializer serializer = MarkdownDocSerializer(doc=doc) ser_text = serializer.serialize().text

6. 实战二:配置 Serializer——替换表格序列化器与参数

同一 Notebook 演示了如何「重配置」Markdown 序列化,满足两类诉求:

  • 使用不同的组件序列化器:例如把表格输出改为 triplet 形式(行1, 列A = 值1. 行1, 列B = 值2. ...),笔记指出这种扁平键值对形式有助于向量检索场景下的表格表示;
  • 使用用户自定义参数:例如替换默认的图片占位符文本。
from docling_core.transforms.chunker.hierarchical_chunker import TripletTableSerializer from docling_core.transforms.serializer.markdown import MarkdownParams serializer = MarkdownDocSerializer( doc=doc, table_serializer=TripletTableSerializer(), # 替换组件级序列化器 params=MarkdownParams( image_placeholder="<!-- demo picture placeholder -->", # ... 其余 MarkdownParams 参数按需提供 ), ) ser_text = serializer.serialize().text

从 Notebook 的实际输出对比可以验证两处差异:同一张 IBM/Starbucks ESG 表格,默认配置下是| Report | Question | Answer |管道表格;换成TripletTableSerializer后变为IBM 2022, Question = ...?. IBM 2022, Answer = ...的连续文本串;同时图片占位符也从默认的<!-- image -->变成了配置中的<!-- demo picture placeholder -->。这直接印证了第 1 节所说的组件级替换机制:只动一个子序列化器,文档其余部分的输出完全不受影响。

7. 实战三:编写自定义 Serializer

当现有实现都不满足时,你可以定义自定义序列化逻辑。Notebook 给出的例子是:让图片序列化额外带上 picture description(图像描述注解)。前提是转换管线开启了 picture description enrichment(通过PdfPipelineOptions(do_picture_description=True, picture_description_options=PictureDescriptionVlmOptions(...), generate_picture_images=True, images_scale=2),并配合PictureDescriptionVlmOptions指定 VLM 模型与 prompt)。

自定义组件序列化器——继承MarkdownPictureSerializer并重写serialize(),先调用父类拿到基础输出,再追加注解:

from docling_core.transforms.serializer.base import BaseDocSerializer, SerializationResult from docling_core.transforms.serializer.common import create_ser_result from docling_core.transforms.serializer.markdown import MarkdownPictureSerializer from docling_core.types.doc.document import DoclingDocument, PictureItem class AnnotationPictureSerializer(MarkdownPictureSerializer): def serialize(self, *, item, doc_serializer, doc, separator=None, **kwargs): text_parts = [] # 复用父类结果(占位符/图片引用部分) parent_res = super().serialize(item=item, doc_serializer=doc_serializer, doc=doc, **kwargs) text_parts.append(parent_res.text) # 追加 picture description 注解 if item.meta is not None and item.meta.description is not None: text_parts.append(f"<!-- Picture description: {item.meta.description.text} -->") text_res = (separator or "\n").join(text_parts) return create_ser_result(text=text_res, span_source=item)

注意create_ser_result(text=..., span_source=item):它把序列出的文本与源组件(item)绑定,形成serialize()契约中「哪些组件贡献了输出」的元数据。然后把自定义图片序列化器挂到文档级序列化器上:

serializer = MarkdownDocSerializer( doc=doc, picture_serializer=AnnotationPictureSerializer(), params=MarkdownParams(image_mode=ImageRefMode.PLACEHOLDER, image_placeholder=""), ) ser_text = serializer.serialize().text

运行后,Markdown 输出中每个图片占位处都会带上一条<!-- Picture description: ... -->注释,内容即管线阶段由 VLM 生成的图片描述。

Notebook 还覆盖了另一个常见诉求——为每张图片生成唯一标识以便下游与原始DoclingDocument匹配:自定义_serialize_image_part(),从item.self_ref解析出图片索引,并对image_placeholder中的{index}占位 token 做替换,配合params=MarkdownParams(image_mode=ImageRefMode.PLACEHOLDER, image_placeholder="<!-- image_{index} -->"),即可让每张图在导出文本中拥有形如<!-- image_2 -->的独立编号。

8. 小结与延伸阅读

  • 序列化是 Docling 转换管线之后的独立层:DoclingDocumentexport_to_*方法只是预置 serializer 的快捷封装,需要精细控制时直接实例化MarkdownDocSerializer/HTMLDocSerializer等并传入组件级序列化器与Params
  • 选择导出格式的核心判据之一是表格 span 保真度:JSON/Doclang/DocTags/HTML 保留完整结构,Markdown/LaTeX 当前会拍平;
  • 组件级 serializer 可任意替换(table、picture、list……),文档级策略可整体替换,扩展点是子类化而非修改管线。

进一步阅读:docs/concepts/docling_document.md(DoclingDocument数据结构)、docs/examples/serialization.ipynb(完整可运行示例,含上述全部代码)、docs/examples/batch_convert.py 与 docs/examples/custom_convert.py(批量/自定义转换中的多格式导出落地)、docs/examples/export_figures.py 与 docs/examples/export_tables.py(图片与表格的独立导出)。

【免费下载链接】doclingGet your documents ready for gen AI项目地址: https://gitcode.com/GitHub_Trending/do/docling

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 20:36:25

雷赛MA860H步进驱动器维修测试流程详解

这次我们来看雷赛 MA860H 这台步进驱动器的维修测试流程。MA860H 是脉冲型数字式步进驱动器&#xff0c;常见搭配两相混合式步进电机使用&#xff0c;尤其是在 86 机座电机驱动的中小型自动化设备、绕线机、送料机构这类现场。它本身不是软件插件&#xff0c;没有 WebUI、没有 …

作者头像 李华
网站建设 2026/9/5 20:33:40

Django云招聘系统:动态供需匹配引擎实战

简介&#xff1a;本资源是一个基于Django框架实现的云招聘系统完整项目源码包&#xff0c;面向Python Web开发初学者与求职类应用实践者&#xff0c;解决招聘信息自动化采集、结构化存储与可视化展示的一站式需求。项目涵盖爬虫模块&#xff08;抓取主流招聘平台职位数据&#…

作者头像 李华
网站建设 2026/9/5 20:24:10

免费把Spotify音乐存到本地:spotDL安装与使用教程

免费把Spotify音乐存到本地&#xff1a;spotDL安装与使用教程 【免费下载链接】spotify-downloader Download your Spotify playlists and songs along with album art and metadata (from YouTube if a match is found). 项目地址: https://gitcode.com/GitHub_Trending/sp/…

作者头像 李华