- 后端
- AI 应用
- NLP
【免费下载链接】xberg
Polyglot document intelligence with a Rust core: extract text, metadata, images, tables, and structured data from 106 formats across 140 file extensions, plus code intelligence for 371 languages. Fifteen bindings, with CLI, REST API, and MCP server.
本指南以 xberg 仓库中 Elixir 契约用例(contract fixture)table_access为主线,讲解如何通过Xberg.ExtractInput与Xberg.extract_async/2从 HTML 文档中提取结构化表格,并逐一访问每个表格的单元格数组与 Markdown 渲染结果。读完本文,你将掌握 xberg Elixir 绑定的表格提取调用方式、tables字段的数据形态,以及契约测试对提取结果的校验口径,可直接用于文档解析、RAG 数据准备等场景。
契约用例概述:table_access到底在测什么
docs-site/src/snippets-generated/elixir/contract/table_access.md是 xberg 仓库中由 alef 工具自动生成的契约(contract)代码片段,其配套的契约定义位于 fixtures/contract/table_access.json。该用例的核心目标只有一个:从 HTML 输入中提取表格,并迭代访问表格的结构化单元格(cells)与 Markdown 输出(markdown)。
在 table_access.json 中,用例被描述为:
- topic:
contract,即跨语言契约一致性用例; - title:
Access extracted tables; - description:
Iterate through structured table cells and Markdown output; - tags:
contract、tables、html; - call:
extract,走的是单文档提取入口; - side_effects:
server,即需要 mock server 提供远程 HTML 文档。
这意味着该用例不只验证 Elixir 一种语言,而是通过同一份 JSON 契约驱动 Java、Rust、Go、Python、TypeScript、C#、Ruby、Swift、Dart、Zig、PHP、Kotlin 等全部绑定生成等价代码(仓库中 docs-site/src/snippets-generated 下每个语言目录的contract/table_access.md均由同一 fixture 生成),从而保证“表格提取结果”在所有语言绑定上结构一致。本文聚焦 Elixir 版本,但其中对tables[].cells与tables[].markdown的理解,可直接平移到其他绑定。
构造输入:Xberg.ExtractInput结构体
在 Elixir 绑定中,所有公开提取入口都接收统一输入结构体Xberg.ExtractInput。其定义位于 packages/elixir/lib/xberg/extract_input.ex,类型声明如下:
@type t :: %__MODULE__{ kind: Xberg.ExtractInputKind.t(), bytes: binary() | nil, uri: String.t() | nil, mime_type: String.t() | nil, filename: String.t() | nil, config: Xberg.FileExtractionConfig.t() | nil } defstruct kind: :uri, bytes: nil, uri: nil, mime_type: nil, filename: nil, config: nil契约用例使用的是uri输入方式,即让引擎去抓取远程文档:
input_value = %Xberg.ExtractInput{ kind: "uri", mime_type: "text/html", uri: "https://example.com/html/simple_table.html" }各字段的语义如下:
| 字段 | 取值 | 说明 |
|---|---|---|
kind | "uri"或"bytes" | 输入来源:uri表示按地址抓取,bytes表示直接传入二进制内容 |
mime_type | "text/html"等 | 声明文档类型,帮助引擎选择正确的提取器 |
uri | 文档 URL | 当kind为uri时必填,指向待解析文档 |
bytes | 二进制 | 当kind为bytes时填充,本例未使用 |
filename | 文件名 | 可选,用于推断格式 |
config | 提取配置 | 可选,按文件粒度覆盖全局配置 |
注意Xberg.ExtractInput实现了Jason.Encoder,在 extract_input.ex 中会剔除所有nil字段后再序列化,因此未使用的bytes、filename、config不会出现在请求负载中。
发起提取:Xberg.extract/1与extract_async/2
契约用例直接调用Xberg.extract_async(input_value, "{}"),其中第二个参数是字符串形式的配置(这里为空对象"{}",表示使用全部默认配置)。在高阶 API 层,packages/elixir/lib/xberg.ex 还提供了更符合 Elixir 惯例的关键字参数封装:
@spec extract(keyword()) :: {:ok, map()} | {:error, atom, String.t()} def extract(opts \\ []) do Xberg.Native.extract_async( case Keyword.get(opts, :input) do nil -> nil v when is_binary(v) -> v v -> Jason.encode!(v) end, case Keyword.get(opts, :config) do nil -> nil v when is_binary(v) -> v v -> Jason.encode!(v) end ) end也就是说,input既可以是已编码的 JSON 字符串,也可以是任意结构(自动通过Jason.encode!/1序列化)。等价写法可以是:
input_value = %Xberg.ExtractInput{ kind: "uri", mime_type: "text/html", uri: "https://example.com/html/simple_table.html" } {:ok, result} = Xberg.extract(input: input_value, config: "{}")extract_async/2底层由 NIF(Xberg.Native,见 packages/elixir/lib/xberg/native.ex 与 packages/elixir/native/xberg_nif/src/lib.rs)转发给 Rust 核心引擎,返回{:ok, map()} | {:error, atom, String.t()}。若需同时处理多个文档,可使用 xberg.ex 中的extract_batch/1。
读取结果:results[0].tables中的cells与markdown
提取结果按“文档 → 结果列表”组织,result.results中每个元素对应一个输入文档(单输入时索引为 0)。契约用例的核心迭代逻辑如下:
Enum.each(Enum.at(result.results, 0).tables, fn table -> IO.inspect(table.cells) IO.inspect(table.markdown) end)这里揭示了tables元素的两种访问方式:
table.cells:结构化单元格数据,通常表现为按行组织的单元格集合(含行列坐标、文本内容等),适合程序化处理——例如把单元格填入二维数组、做数值清洗或喂给下游模型;table.markdown:同一表格渲染成 Markdown 表格语法(| Product | Category |形式)的文本,适合直接嵌入 Markdown 文档、LLM 提示词或用于人类阅读。
table.cells与table.markdown是同一表格的两种视角:前者是结构化的机器可读形态,后者是便于人读和落盘的文本形态。在实际管线中,常见做法是先用cells做结构化校验/转换,再用markdown直接输出或入库。
契约断言:提取结果的验收标准
契约用例的“正确性”由 fixtures/contract/table_access.json 中的assertions定义,共三条,可作为我们调试时的验收清单:
{ "assertions": [ { "type": "equals", "field": "results[0].mime_type", "value": "text/html" }, { "type": "count_min", "field": "results[0].tables", "value": 2 }, { "type": "contains_all", "field": "results[0].tables[0].markdown", "values": ["Product", "Category", "Laptop", "$999.99"] } ] }含义分别为:
results[0].mime_type == "text/html":引擎正确识别了输入文档的 MIME 类型;results[0].tables数量 ≥ 2:示例 HTML 至少被识别出两张表格;tables[0].markdown同时包含Product、Category、Laptop、$999.99:第一张表的 Markdown 文本完整保留了表头(Product / Category)与首行数据(Laptop / $999.99),即表头、单元格文本都没有丢失。
第三条对表格提取质量提出了硬性要求:Markdown 输出必须保留原始表格的所有文本信息,这正是在线表格解析(HTML 表格 → 结构化数据 → Markdown)的核心验收点。该 fixture 还通过mock_responses配置了https://example.com/html/simple_table.html的 mock 响应(status_code: 200,content-type: text/html),说明该用例由scripts/e2e/run-with-mock-server.sh这类 mock server 支撑运行,不依赖真实外网。
契约一致性:同一用例在 Python / TypeScript 中的形态
table_access是跨语言契约,因此理解 Elixir 写法后,对照其他绑定可以更清楚地看出“哪些是引擎能力、哪些是语言封装”。以 Python 版本 为例:
from xberg import extract, ExtractInput, ExtractInputKind from xberg._xberg import ExtractionConfig input = ExtractInput(kind=ExtractInputKind("uri"), mime_type="text/html", uri="https://example.com/html/simple_table.html") config = ExtractionConfig.from_json("{}") result = await extract(input, config) for table in result.results[0].tables: print(table.cells) print(table.markdown)再以 TypeScript 版本 为例:
const input: ExtractInput = { kind: ExtractInputKind.Uri, mimeType: "text/html", uri: "https://example.com/html/simple_table.html" }; const result = await extract(input); for (const table of result.results[0]?.tables ?? []) { console.log(table.cells); console.log(table.markdown); }三种语言的骨架完全一致:构造ExtractInput(uri + mime_type)→ 调用extract→ 遍历results[0].tables→ 访问cells与markdown。这印证了表格提取的结果模型是引擎级统一约定,语言绑定只负责序列化与类型封装。
实战要点与扩展方向
- 表格提取不限于 HTML:本例以
text/html演示,但 xberg 的提取引擎覆盖 106 种格式(详见 README.md 中的格式清单),PDF、DOCX、XLSX 等文档中的表格同样会进入results[].tables,只是cells的坐标与文本组织方式随来源略有差异。 - 用
cells做结构化处理,用markdown做人读输出:需要数值运算、单元格对齐或按行列过滤时优先读cells;需要把结果直接粘进文档、提示词或数据库时用markdown。 - 善用契约断言做回归验证:在集成测试中可仿照
table_access.json的count_min与contains_all写法,对真实文档断言“至少提取 N 张表”和“关键文本不丢失”,这是保障解析质量的最低成本手段。 - 异步 API 语义:
extract_async/2在 NIF 层以异步方式执行,避免阻塞 BEAM 调度器,适合在 Phoenix 或 GenServer 中并发调用;批量场景优先使用extract_batch/1以减少往返。
本文对应的完整可运行契约代码位于 docs-site/src/snippets-generated/elixir/contract/table_access.md,其生成源与断言定义位于 fixtures/contract/table_access.json;Elixir 绑定 API 可继续查阅 packages/elixir/lib/xberg.ex 与 packages/elixir/lib/xberg/extract_input.ex。
- 后端
- AI 应用
- NLP
【免费下载链接】xberg
Polyglot document intelligence with a Rust core: extract text, metadata, images, tables, and structured data from 106 formats across 140 file extensions, plus code intelligence for 371 languages. Fifteen bindings, with CLI, REST API, and MCP server.
相关推荐
xberg C 表格访问实战:通过 ExtractAsync 提取并遍历结构化单元格与 Markdown 输出
xberg C 表格访问实战:通过 ExtractAsync 提取并遍历结构化单元格与 Markdown 输出 本文基于 xberg 仓库中的 table_ac
后端AI 应用NLPEvolver第一次运行全解析:一次进化周期里到底发生了什么
Evolver第一次运行全解析:一次进化周期里到底发生了什么 Evolver 是一个由 GEP(Genome Evolution Protocol,基因组进化协
后端AI 应用NLPPaddleOCR表格识别:结构化数据提取
PaddleOCR表格识别:结构化数据提取 痛点场景:从混乱图像到结构化数据的鸿沟 在日常工作和数据处理中,我们经常面临这样的困境:大量的表格数据以图片形式存在
人工智能计算机视觉OCR深度学习大模型RAG
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考