news 2026/9/8 23:30:57

Duck Observations

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Duck Observations

Duck Observations

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

| Number of freshwater ducks per year | | - |

| Year | Freshwater Ducks | | - | - | | 2019 | 120 | | 2020 | 135 | | 2021 | 150 | | 2022 | 170 | | 2023 | 160 | | 2024 | 180 |

可以看出:工作表名被序列化为一个二级标题,而正文内容**不是一整张大表**,而是被切分成了“一个 1×1 的标题表格”和“一个 7×2 的数据表格”两个独立的 `TableItem`。这正是 Docling Excel 后端区域探测算法的直接体现。 ## 二、为什么标题没有变成正文文本,而是成为一张 1×1 表格 很多读者第一眼会疑惑:`Number of freshwater ducks per year` 明显是个标题,为什么在默认输出里它表现为一张孤零零的 1×1 表,而不是一段文本? 答案藏在 Excel 后端的两个行为中: 1. **断连区域会被解析成不同表格**。在 [msexcel_backend.py](https://link.gitcode.com/i/4df4451c4f2f781193a9cef8aec7168c) 的类文档字符串中写明:“Cell contents, parsed as tables. If two groups of cells are disconnected between each other, they will be parsed as two different tables.” 结合 JSON 真值中两张表的 `prov.bbox` 可以发现:标题簇占据 `t=1 → b=2`,数据表簇占据 `t=3 → b=10`,两者之间存在一整行的空隙。因此基于 Flood Fill(BFS)的连通域探测把该工作表识别为**两个互不连通的单元格簇**,各生成一张 `TableItem`。 2. **`treat_singleton_as_text` 默认是 `False`**。在 [MsExcelBackendOptions](https://link.gitcode.com/i/e1b6476442423a2c4ae7f1f65672804b) 中,该选项被定义为: ```python treat_singleton_as_text: bool = Field( False, description=( "Whether to treat singleton cells (1x1 tables with empty neighboring " "cells) as TextItem instead of TableItem." ), )

因为后端默认并不启用该选项,所以被孤立出来的 1×1 标题簇不会升级为TextItem,而是保持为一张 1×1 的TableItem。对应逻辑位于 msexcel_backend.py:只有当treat_singleton_as_text=True且该表恰好只有一个数据单元格时,才会通过doc.add_text(...)把它输出为正文文本。

这也解释了为什么 Markdown 真值第一行会出现单列表格:

| Number of freshwater ducks per year | | - |

这是一张“只有表头、没有数据行”的紧凑型单列表:它的唯一单元格位于第 0 行(column_header: true),序列化后生成表头行,再用| - |作为分隔行。

三、从 JSON 真值看懂单元格语义标注

阅读 xlsx_05_table_with_title.xlsx.json 可以从内部结构上验证上述行为:

  • 文档body下只有一个groups/0,其nameDuck Observationslabelsheet,即整个工作表被建模为一个 sheet 分组(GroupItem),这正是 Markdown 中## Duck Observations标题的来源;
  • texts数组为空——说明在默认选项下没有产生任何正文文本;
  • tables数组包含两张表:
    • tables/0:1 行 1 列,单元格文本为Number of freshwater ducks per year,语义标志为"column_header": true(因为该单元格位于第 0 行),没有合并跨行跨列(row_span/col_span均为 1);
    • tables/1:7 行 2 列。首行YearFreshwater Ducks均被标注为column_header: true,其后 2019–2024 共 6 行数值单元格的column_header均为false

单元格层面的column_header/row_header/row_section布尔标志,正是 Docling 在文档中保留的表格语义元数据。它来自后端的建表逻辑:在 msexcel_backend.py 中,每个 Excel 单元格被转换为TableCell时执行column_header=excel_cell.row == 0——即只要单元格处于第 0 行就被视为列头。这让数据表的表头行与普通数据行在结构化层面得到明确区分,为后续面向 RAG 的切片、表格导出乃至 HTML 渲染提供了可靠依据。

四、从 itxt 真值看文档层级

xlsx_05_table_with_title.xlsx.itxt 用缩进文本直观呈现了同一份文档的树形结构:

item-0 at level 0: unspecified: group _root_ item-1 at level 1: sheet: group Duck Observations item-2 at level 2: table with [1x1] item-3 at level 2: table with [7x2]

它验证了三个关键信息:整个工作表内容都挂在一个sheet分组下;该分组直接包含两张表格子节点;两张表的尺寸分别是[1x1][7x2],与 Markdown/JSON 真值完全一致。对于希望调试“为什么我的表被拆开了”的读者,itxt是比 JSON 更快的定位工具。

五、真值文件如何在测试中被使用

tests/data/xlsx/groundtruth/下的三份产物会被 test_backend_msexcel.py 中的两处测试消费:

5.1 端到端回归测试(默认选项)

test_e2e_excel_conversions(见 test_backend_msexcel.py)用默认DocumentConverter依次转换tests/data/xlsx/sources/下所有工作簿,然后:

  • 使用 docling_core 的MsExcelMarkdownDocSerializer,以MarkdownParams(compact_tables=True, layers=DEFAULT_CONTENT_LAYERS)序列化 Markdown,并与.md真值比对;
  • 使用doc._export_to_indented_text(...).itxt真值比对;
  • 使用verify_document(..., fuzzy=True).json真值比对。

因为默认转换没有启用treat_singleton_as_text,标题单元格被保留成 1×1 表格,所以.md真值中出现两张表——这与默认 e2e 的比对设定是自洽的。

5.2 选项行为测试(开启 treat_singleton_as_text)

test_table_with_title(见 test_backend_msexcel.py)则专门验证反向行为:显式构造MsExcelBackendOptions(treat_singleton_as_text=True)并注入ExcelFormatOption后再转换同一文件,此时断言结果变为:

assert len(doc.texts) == 1 # 标题变成了一个 TextItem assert len(doc.tables) == 1 # 只剩 7x2 的数据表 assert doc.texts[0].text == "Number of freshwater ducks per year" assert table.data.num_rows == 7 and table.data.num_cols == 2

对照读这两处测试,就能完整理解同一份源文件在不同选项下“标题究竟是正文还是表”的输出差异,也说明了真值文件.md(默认选项)与test_table_with_title(开启选项)并不矛盾,而是覆盖了两种合法配置。

六、自己动手复现与验证

在仓库环境中可用以下方式复现该真值(默认选项下应得到与.md文件一致的输出):

from docling.document_converter import DocumentConverter from docling.datamodel.base_models import InputFormat converter = DocumentConverter(allowed_formats=[InputFormat.XLSX]) result = converter.convert( "tests/data/xlsx/sources/xlsx_05_table_with_title.xlsx" ) doc = result.document print(doc.export_to_markdown()) print(doc._export_to_indented_text(max_text_len=70, explicit_tables=False))

如需复现“标题升级为正文文本”的路径,把MsExcelBackendOptions通过ExcelFormatOption传入即可:

from docling.document_converter import DocumentConverter, ExcelFormatOption from docling.datamodel.base_models import InputFormat from docling.datamodel.backend_options import MsExcelBackendOptions options = MsExcelBackendOptions(treat_singleton_as_text=True) converter = DocumentConverter( allowed_formats=[InputFormat.XLSX], format_options={InputFormat.XLSX: ExcelFormatOption(backend_options=options)}, ) doc = converter.convert( "tests/data/xlsx/sources/xlsx_05_table_with_title.xlsx" ).document print(list(doc.texts)[0].text) # Number of freshwater ducks per year print(list(doc.tables)[0].data.num_rows, "x", list(doc.tables)[0].data.num_cols)

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

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

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

STM32F407VET6为何仍是主流?从选型到以太网应用实战解析

STM32F407VET6这颗料,放在2024年怎么看都不算年轻了——2011年发布,Cortex-M4内核,主频168MHz,工艺还是老的90nm级别。但你要是打开电商平台搜一搜,或者去GitHub上翻开源项目,会发现这颗芯片的出镜率高得离…

作者头像 李华
网站建设 2026/9/8 23:30:26

res-downloader 使用教程:捕获视频资源并处理加密视频

res-downloader 使用教程:捕获视频资源并处理加密视频 【免费下载链接】res-downloader 视频号、小程序、抖音、快手、小红书、直播流、m3u8、酷狗、QQ音乐等常见网络资源下载! 项目地址: https://gitcode.com/GitHub_Trending/re/res-downloader res-downlo…

作者头像 李华
网站建设 2026/9/8 23:30:10

PROFIBUS DP编码器GSD文件导入与通讯故障排查指南

简介:帝尔编码器TR CMV582M-00022的GSD文件包,面向工业自动化现场调试与PLC编程工程师,解决该型号编码器在PROFINET网络中的设备描述与组态导入问题。压缩包共9个文件,包含5个XML格式的GSDML描述文件,覆盖V2.32至V2.35…

作者头像 李华
网站建设 2026/9/8 23:29:43

离线 IP 定位 10 微秒级响应:ip2region 多语言实战与选型

离线 IP 定位 10 微秒级响应:ip2region 多语言实战与选型 【免费下载链接】ip2region Ip2region is an offline IP-to-Region localization library and IP data management framework with both IPv4 and IPv6 supports, 10-microsecond level query efficiency, x…

作者头像 李华
网站建设 2026/9/8 23:28:42

GitLab自托管实战:从Docker部署到CI/CD高频操作与避坑

1. GitLab是谁,为什么值得折腾先聊一个看着有点傻、但几乎每天都会有人问的问题:GitLab 到底是干嘛的?它本质上就是一套可以自己部署的代码托管平台,跟 GitHub、Gitee 做的事差不多——管理代码仓库、处理合并请求、跑 CI/CD 流水…

作者头像 李华