Tables and forms
Three shapes, because documents contain three different things that look like tables:
| Type | For | Entry |
|---|---|---|
Table | A detected table with headers and rows | bbox.Doc().Table(), .TableWith(text) |
Rows | A column-aligned section that is not a real table | bbox.Doc().Rows(start, end) |
Form | A named form with labelled fields | bbox.Doc().Form(name) |
All three answer Found(), Missing() and Reason(), so a rule can check before reading and say
why when nothing came back.
| Call | Returns | Gives |
|---|---|---|
Cell(row, col) | Value | One cell by numeric position |
At(row, header) | Value | One cell by row index and header name |
Row(index) | Row | One row by position |
RowWith(text) | Row | The row containing that text |
Column(header) | list of Value | A whole column — .Len() only |
Headers() | list | The header names — .Len() only |
HasHeader(header) | bool | Whether a header is present |
RowCount() | number | How many rows |
ColumnCount() | number | How many columns |
Page() | number | Which page the table is on |
Records() | list of maps | Every row — hand straight to out.Set |
Found() / Missing() / Reason() | bool / bool / string | Whether a table was located, and why not |
when bbox.Doc().Table().HasHeader("Amount")then out.Set("line_items", bbox.Doc().Table().Records());| Call | Returns | Gives |
|---|---|---|
Get(header) | Value | The cell under that header |
Cell(col) | Value | The cell at that position |
Index() | number | Which row this is |
Found() / Reason() | bool / string | Whether the row was located, and why not |
out.Set("total", bbox.Doc().Table().RowWith("Total").Get("Amount").Currency().Str());For sections that line up in columns without being detected as a table — the common case in scanned forms. You describe the columns you want, then take the records.
| Call | Returns | Gives |
|---|---|---|
Col(header, name, kind...) | Rows | Take the column under header, output it as name |
ColNth(header, occurrence, name, kind...) | Rows | The nth column with that header |
ColRightOf(anchor, header, name, kind...) | Rows | The column right of an anchor |
ColUnder(anchor, header, name, kind...) | Rows | The column under an anchor |
Describe(name, kind...) | Rows | Type the named output column |
Number(name) | Rows | Coerce that column to a number |
SplitOn(delimiter, tailName) | Rows | Split a column, putting the tail in tailName |
Strip(chars) | Rows | Strip characters from every cell |
Count() | number | How many rows |
Records() | list of maps | The rows — hand straight to out.Set |
Found() / Reason() | bool / string | Whether the section was located, and why not |
The kind argument is optional and names the value type for that column.
out.Set("employers", bbox.Doc().Rows("Employment History", "Income") .Col("Employer", "employer") .Col("Start", "start_date") .Number("years") .Records());| Call | Returns | Gives |
|---|---|---|
Get(field) | Value | One field by name |
Has(field) | bool | Whether the field is present |
Name() | string | The form’s name |
FieldCount() | number | How many fields |
Fields() | map | Every field — hand to out.Set, or take .Len() |
Found() / Reason() | bool / string | Whether the form was located, and why not |
when bbox.Doc().HasForm("1003")then out.Set("borrower", bbox.Doc().Form("1003").Get("Borrower Name").Str());Getting rows into the output
Section titled “Getting rows into the output”Records() is the call that matters. GRL cannot iterate a list, so a rule never walks rows itself —
it hands the whole collection to out.Set and lets the caller read it:
out.Set("line_items", bbox.Doc().Table().Records());When the receiving format cannot carry an array, flatten it with
delivery.ExplodeColumn instead.