Complex layouts¶
Use explicit sources to separate neighboring tables and exclude known comments without inferring their meaning. Each source has independent bounds; optional per-source rules replace the shared rules rather than merge with them.
Known columns and rows¶
Create layout.xlsx, sheet Data, with these worksheet positions:
,,Customer,Amount,Previous,,Customer,Amount
,,Name,Current,Prior,,Name,Current
,,Comment before data,,,,,
,,one,120,80,,neighbor,999
,,ignore,1000,1000,,ignore,1000
,,two,200,180,,other,250
from chooong.datasift import ColumnBinding, FilterMask, TableSource, iter_matching_rows
mask = FilterMask(
sheet="Data",
source=TableSource(
columns=(
ColumnBinding(name="Customer", column="C"),
ColumnBinding(name="Amount", column="D"),
),
data_start_row=4,
data_end_row=6,
skip_rows=(5,),
),
)
assert [dict(row) for row in iter_matching_rows("layout.xlsx", mask)] == [
{"Customer": "one", "Amount": 120},
{"Customer": "two", "Amount": 200},
]
Headers and unrelated columns are not interpreted in this mode. Alias names are unique; two aliases may bind one physical column. Boundaries and collision rules are defined in column mapping.
Known header windows¶
Bind the first two physical header rows instead of assigning aliases:
mask = {
"sheet": "Data",
"source": {
"header_start_row": 1,
"first_column": "C",
"last_column": "E",
"data_start_row": 4,
"data_end_row": 6,
"skip_rows": [5],
},
"header": {"rows": 2},
}
assert [dict(row) for row in iter_matching_rows("layout.xlsx", mask)] == [
{"Customer Name": "one", "Amount Current": 120, "Previous Prior": 80},
{"Customer Name": "two", "Amount Current": 200, "Previous Prior": 180},
]
header.merged_fill=True fills actual OOXML merged ranges from their top-left
cell; it does not guess missing labels. This requires a streaming metadata pass
before reading data. Use sources for several windows and a source sheet
restriction where needed. Explicit overlaps emit once per source, in declaration
order; automatic regions instead remain non-overlapping.
Comments, totals and separators inside data bounds need explicit row classification or predicates. Corrupt selected values and structural XML errors remain errors even with explicit bounds.