Skip to main content

05 · One sheet per group

Scenario

Same renewal report, one file, but with a separate sheet for each region. Plus a "non-renewable" sheet that filters to a specific list of statuses.

Approach: name the template sheet with a group key

The template sheet name is the sheet template. xl3 expands one sheet per distinct group key value, using the template's contents.

Template sheet name: Region-{{ [Region] }}

xl3 reads the literal name Region-{{ [Region] }}, groups source rows by Region, and emits one sheet per region with the resolved name: Region-Seoul, Region-Busan, etc.

__config__

keyvalue
source_sheetRaw
source_table1
output_file_patternregions.xlsx

Template (sheet name Region-{{ [Region] }})

CellValue
A1Account
B1Renewal
A2{{ [Account] }}
B2{{ [Renewal] }}
A3Total
B3{{ SUM([Renewal]) }}

Data

AccountRegionRenewal
AcmeSeoul18400
BetaBusan7200
CoreonSeoul25100

Output (regions.xlsx)

  • Sheet Region-Seoul: Acme, Coreon, Total=43500.
  • Sheet Region-Busan: Beta, Total=7200.

Filter a sheet to a named list

A common shape: one sheet per group, plus an "all renewals < $5k" sheet filtered to a status list. Use __lists__:

__lists__:
status_active: ["Active", "Renewing"]
status_inactive: ["Cancelled", "Lapsed"]

Then in a sheet template:

Template sheet name: At-Risk
A1: Account | B1: Status | C1: Renewal
A2: {{ @filter [Status] in __lists__[status_active] }}{{ @filter [Renewal] < 5000 }}{{ [Account] }}
B2: {{ [Status] }}
C2: {{ [Renewal] }}

Multiple @filter directives in one block compose with AND. Each filter narrows the previous result.

Notes

  • Sheet name sanitization follows Excel's 31-char limit + forbidden chars ([ ] / \ ? *). Sanitized values that collide are implementation-defined per ADR-0021 — keep group keys distinct upstream.
  • Empty group key → literal (blank) per ADR-0026.
  • Sheet order is first-seen per ADR-0016.