How to Classify PDF Tables by Their Borders (and Why It Matters): LATTICE vs STREAM
TLDR
PDF tables fall into two distinct architectural classes:LATTICE_TABLE (explicit vector grid lines) and STREAM_TABLE (borderless column alignment implied by text $X$-coordinates). Running standard grid cell expansion (colspan/rowspan) on borderless stream tables collapses all cells into a single full-page spanning cell. Setting isBorderless = true disables expansion loops, while distinct CSS wrapper classes (.pdf-table--lattice vs .pdf-table--borderless) preserve semantic rendering.
| Table Architecture | Detection Evidence | Grid Line Input | colspan/rowspan Expansion | CSS Styling Class |
|---|---|---|---|---|
LATTICE_TABLE | Vector Path Segments | $H/V$ Grid Lines | Enabled (Full expansion) | .pdf-table--lattice (Borders) |
STREAM_TABLE | Spatial $X$-Clustering | hLines: [], vLines: [] | Disabled (isBorderless = true) | .pdf-table--borderless (Clean) |
Technical implementation & overlap guard
// Table Builder: Disable colspan/rowspan expansion for borderless stream tables
export function buildTableHtmlGrid(latticeGridData) {
const isBorderless = latticeGridData.hLines.length === 0 && latticeGridData.vLines.length === 0;
if (isBorderless) { // Stream tables skip expansion logic: assign explicit 1x1 cells return renderBorderlessTableHtml(latticeGridData.cells); }
// Lattice tables execute full grid expansion return renderLatticeTableHtml(expandCellSpans(latticeGridData)); }
// Overlap Guard: Prefer physical vector lattice tables over stream heuristics export function resolveTableClassification(latticeTables, streamTables) { const finalTables = [...latticeTables];
for (const streamTable of streamTables) { const overlapCoverage = calculateItemCoverage(streamTable, latticeTables); // Skip stream table if 80%+ of items are already claimed by a physical lattice grid if (overlapCoverage > 0.8) continue; finalTables.push(streamTable); }
return finalTables; }
Rule of thumb: Disablecolspan/rowspanexpansion for borderless stream tables (isBorderless = true) and prioritize vector lattice grids when classifications overlap.