☰
xberg PHP 绑定实战:访问结构化表格单元格与 Markdown 输出
2026/10/9 1:22:38 网站建设 项目流程
  • 后端
  • 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.

项目地址:https://gitcode.com/gh_mirrors/kr/xberg
点击查看免费下载

本篇指南围绕 xberg(Rust 核心的多语言文档智能提取库)的 PHP 绑定,完整讲解如何通过Xberg\ExtractInput构造输入、调用Xberg::extract()提取 HTML/PDF/Office/图片等文档中的表格,并分别以二维单元格数组与渲染好的 Markdown 文本两种形态消费表格数据。读完本文,你将掌握getTables()/getCells()/getMarkdown()等核心 API 的用法,理解Table对象中pageNumber、boundingBox、tableId、columns、cellStyles等字段的语义,并学会用仓库中的端到端测试验证自己的代码。

最小可运行示例:一次提取,双通道读取表格

原始契约文档 docs-site/src/snippets-generated/php/contract/table_access.md 给出的核心示例展示了 xberg PHP 绑定访问表格的完整闭环——构造一个指向 HTML 文档的 URI 输入,执行提取,然后同时读取每个表格的单元格网格和Markdown 文本:

<?php declare(strict_types=1); require_once __DIR__ . '/vendor/autoload.php'; use Xberg\Xberg; use Xberg\ExtractInput; $input = \Xberg\ExtractInput::from_json(json_encode(["kind" => "uri", "mimeType" => "text/html", "uri" => "https://example.com/html/simple_table.html"])); $result = Xberg::extract($input, []); foreach ($result->getResults()[0]->getTables() as $table) { var_dump($table->getCells()); var_dump($table->markdown); }

这段代码虽然只有十余行,却串联起了整个 xberg PHP 表格访问链路,下面逐层拆解。

输入构造:ExtractInput的字段与工厂方法

示例通过\Xberg\ExtractInput::from_json()用一个 JSON 字符串构造输入对象,其背后的 PHP 类定义在 crates/xberg-php/src/lib.rs。ExtractInput携带以下字段:

字段类型说明
kindstring输入来源类型。"bytes"表示原始字节输入(此时须提供bytes);"uri"表示 URI 输入(此时须提供uri)
bytes?stringkind = "bytes"时的原始字节内容
uri?string本地路径、file://URI 或 HTTP(S) URL
mimeType?stringMIME 类型提示,如"text/html"、"application/pdf"
filename?string文件名提示,用于 MIME 探测与元数据
config?FileExtractionConfig单输入粒度的提取配置覆盖

示例中kind = "uri"、mimeType = "text/html"、uri指向一个远程 HTML 页面,这组合是标准的网页/HTML 表格提取姿势。除了from_json()这个通用工厂,绑定还提供了两个语义更明确的构造方法:

  • ExtractInput::fromBytes(bytes, mimeType, filename)——直接喂字节流,适合已读入内存的 PDF、图片、Office 文件;
  • ExtractInput::fromUri(uri)——只给 URI(本地路径、file://或 HTTP(S) URL),MIME 由引擎自动探测。

from_json内部调用serde_json::from_str解析,如果 JSON 结构非法会抛出带具体错误信息的PhpException。

提取调用链:从Xberg::extract到getResults()[0]->getTables()

示例调用Xberg::extract($input, []),第二个参数为空数组表示使用全默认ExtractionConfig。绑定层实现位于 crates/xberg-php/src/lib.rs:它把 PHP 对象转换为核心 Rust 的xberg::ExtractInput与xberg::ExtractionConfig,在WORKER_RUNTIME上block_on异步执行真正的xberg::extract(),最后把 Rust 结果整体转回 PHP 对象返回。

返回值是Xberg\ExtractionResult(crates/xberg-php/src/lib.rs),它包含:

  • results——按发现顺序排列的提取文档列表,即getResults();
  • errors——非致命、按输入归类的错误;
  • summary——本次操作的聚合统计;
  • crawlFinalUrls/crawlRedirectCount/crawlUniqueNormalizedUrls——URL 抓取相关的跳转与去重信息。

每个结果是一个ExtractedDocument(crates/xberg-php/src/lib.rs),getTables()(crates/xberg-php/src/lib.rs)返回该文档中识别出的全部表格对象数组。所以$result->getResults()[0]->getTables()的语义就是"第一个文档里所有被提取出来的表格"。

Table对象深度解析:单元格、Markdown 与位置信息

PHP 侧的Xberg\Table类定义在 crates/xberg-php/src/lib.rs,它直接镜像 Rust 核心类型 crates/xberg/src/types/tables.rs。一个Table包含以下属性:

属性访问器类型语义
cellsgetCells()array<array<string>>表格单元格的二维数组,cells[row][col],行 × 列结构
markdowngetMarkdown()string该表格渲染好的 Markdown 文本(如| A | B |\n|---|---|\n| C | D |)
pageNumbergetPageNumber()int表格所在页码,从 1 开始
boundingBoxgetBoundingBox()?BoundingBox表格位置边界框,仅当产生该表格的提取器提供了位置数据时才填充
tableIdgetTableId()?string稳定标识符,用于把tables[]与content/pages[].content/chunks[].content中的 Markdown 块对应起来
columnsgetColumns()?array<string>表头单元格(即cells的第一行),即使该表格自身的表头行被合并掉也会填充,保证单个表格片段可独立解读
cellStylesgetCellStyles()array<TableCellStyle>带段落样式的单元格列表(稀疏、扁平设计),如 DOCX 标题行

关于boundingBox坐标系,必须知道的约定

boundingBox的坐标空间取决于表格由哪条管线产出,使用前必须先弄清来源(见 crates/xberg/src/types/tables.rs):

  • PDF 原生内容提取的表格,以及扫描版 PDF 经过 OCR 管线(--force-ocr/--ocr-scanned-pages)识别出的表格:坐标单位为PDF 磅(points),原点在左下角(x 向右、y 向上)。OCR 场景下,管线会把后端的像素坐标先经过rescale_ocr_bboxes_to_page_points(实现在 crates/xberg/src/extractors/pdf/ocr/document.rs)缩放到该坐标系;
  • 纯图片(PNG/JPEG/TIFF)直接提取、OCR 检测出的表格:坐标是光栅像素坐标,原点在左上角(x 向右、y 向下),与 OCR 后端(Tesseract、PaddleOCR、candle 系后端)或版面检测器上报的原始像素框一致,因为没有 PDF 页面几何可缩放,直接原样透传。

tableId:跨通道对齐表格的关键

tableId由提取管线确定性地分配(按文档顺序生成"table-N"这类序号,绝不依赖随机数或墙钟时间),因此同一输入文档每次提取都会得到相同的 id(crates/xberg/src/types/tables.rs)。它的典型用途:把结构化tables[]条目与 Markdown 文本流(content、pages[].content、chunks[].content)中的表格块做关联,实现"既保留了全文 Markdown,又能精确知道每张表的结构"。需要注意:跨页拆分的表格目前不会共享同一个 id——每个页内片段各自独立编号。

cellStyles:处理"表头即标题"的特殊表格

cellStyles(对应类型TableCellStyle,见 crates/xberg/src/types/tables.rs)保存单元格携带的段落样式,字段为row、col(零基下标,指向cells)、headingLevel(1–6 级标题,非标题则为空)、styleName(如heading 2)。这是一个稀疏、扁平的结构——只有真正带样式的单元格才会出现条目,所以普通表格序列化后与从前完全一致。它解决的真实痛点:DOCX 中的横幅行(第 0 行、整行跨列、样式为Heading1..Heading6)是 Word 导航窗格与TOC字段眼中的文档大纲,但作为表格单元格它原本只能以匿名文本到达消费者;cells保持纯文本(给单元格文本加#前缀会在表格内部产生非法 Markdown 标题),样式信号则独立放进cellStyles。

引擎内部:表格是如何被"提取"出来的

xberg 的表格提取并非单一算法,而是按文档类型走不同管线,最终都归一为统一的Table结构:

  • HTML:HtmlExtractor支持text/html与application/xhtml+xml两种 MIME(crates/xberg/src/extractors/html.rs)。测试辅助函数extract_tables(crates/xberg/src/extractors/html.rs)展示了其内部链路:convert_html_to_markdown_with_tables解析 HTML 得到TableData(含网格grid与 Markdown 文本),再经flatten_positioned_cells把带row_span/col_span的定位单元格展平为规整的Vec<Vec<String>>,最后组装成Table { cells, markdown, page_number: i + 1, bounding_box: None }。这就是示例文档走的路——HTML 表格位置信息天然缺失,boundingBox为None。
  • PDF 原生:NativeDocument::extract_tables_native(crates/xberg/src/pdf/native/table.rs)以及extract_tables_bordered(有边框表格)、extract_tables_heuristic(启发式表格)构成 PDF 侧的表格识别族。
  • OCR 识别:扫描页经 OCR 管线得到的是RecognizedTable(PHP 侧见 crates/xberg-php/src/lib.rs,含detectionBbox、cells、markdown),再经坐标缩放、缝合(stitching)等步骤归入统一tables[]。

Rust 核心类型 crates/xberg/src/types/tables.rs 自带的单元测试直接给出了Table的 JSON 形态样例:cells为二维数组,markdown为管道表格文本,page_number为 1,bounding_box形如{"x0":50.0,"y0":100.0,"x1":500.0,"y1":700.0},并验证了含bounding_box时的序列化往返。

端到端验证:仓库中的test_table_access测试

仓库为本文核心示例提供了对应的端到端契约测试,位于 e2e/php/tests/ContractTest.php。测试通过环境变量MOCK_SERVER_URL指向 mock 服务器,把$mock_url/html/simple_table.html作为 URI 输入(与契约 fixture fixtures/contract/table_access.json 对应),然后断言:

$results0Tables = $result->getResults()[0]->getTables(); $this->assertEquals("text/html", $result->getResults()[0]->mimeType); $this->assertGreaterThanOrEqual(2, count($results0Tables)); $this->assertStringContainsString("Product", $result->getResults()[0]->getTables()[0]->markdown); $this->assertStringContainsString("Category", $result->getResults()[0]->getTables()[0]->markdown); $this->assertStringContainsString("Laptop", $result->getResults()[0]->getTables()[0]->markdown); $this->assertStringContainsString("$999.99", $result->getResults()[0]->getTables()[0]->markdown);

从中可以提炼出三个可靠的行为约定:

  1. MIME 回传:提取结果的mimeType与输入提示一致("text/html");
  2. 表格数量:这个simple_table.html样例至少产生 2 个表格条目(assertGreaterThanOrEqual(2, ...));
  3. Markdown 保真:表头单元格(Product、Category)与数据单元格(Laptop、$999.99)都完整出现在markdown字段里——说明 HTML 表格的文本内容没有在转换过程中丢失。

实战组合:把表格用于你的 PHP 项目

将表格转成关联数组

getCells()返回规整的二维字符串数组,第一行即表头(getColumns()是其冗余暴露,跨片段场景下更可靠),可以直接转成按列名索引的行记录:

$table = $result->getResults()[0]->getTables()[0]; $cells = $table->getCells(); $headers = $cells[0] ?? []; $rows = []; foreach (array_slice($cells, 1) as $row) { $rows[] = array_combine($headers, array_pad($row, count($headers), '')); }

直接消费 Markdown

$table->markdown(等价于getMarkdown())是已经渲染好的标准管道表格,可直接拼进全文、落盘或喂给下游 LLM/RAG 管线;$table->getTableId()可用来反向定位这段 Markdown 在全文中的归属。

页面与位置过滤

多页文档用getPageNumber()筛选指定页的表格;带位置数据的结果(PDF 原生或扫描页 OCR)用getBoundingBox()拿到边界框做版面分析。务必按上一节说明确认坐标系后再解释坐标值。

批量场景

Xberg::extractBatch()(crates/xberg-php/src/lib.rs)接受多个ExtractInput并同样返回ExtractionResult,适合批量文档的表格抽取,getResults()的下标即输入顺序。

关键约定小结

  • cells始终是纯文本的二维网格;带样式的单元格信息走cellStyles,不要试图往cells里塞 Markdown/标题语法。
  • pageNumber从 1 开始;boundingBox的坐标系必须结合表格来源(PDF 原生/扫描 OCR 为 PDF 磅、左下原点;纯图片 OCR 为像素、左上原点)解释。
  • tableId确定性分配、可跨通道对齐;跨页拆分表格各片段 id 独立。
  • 表格提取按格式分流(HTML 转换器、PDF 原生/边框/启发式、OCR 识别),最终统一收敛为Table,因此同一套 PHP 代码可以无差别处理 HTML、PDF、Office 与图片中的表格。

如需查看 PHP 绑定支持的全部能力与安装方式,可阅读 packages/php/README.md;底层表格类型定义与测试在 crates/xberg/src/types/tables.rs,更多语言的契约样例可在 docs-site/src/snippets-generated/php/contract/ 下继续探索。

  • 后端
  • 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.

项目地址:https://gitcode.com/gh_mirrors/kr/xberg
点击查看免费下载
上一篇:aioredis-py终极指南:从入门到精通的Python异步Redis客户端
下一篇:FossFLOW等距图制作终极指南:7步打造专业级基础设施可视化图表

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询