Basic Concepts
Understanding these core concepts will help you effectively use goxcel.
Templates and Data
Template (GXL File)
A template defines the structure of your Excel file. It's an XML file with .gxl extension that contains:
- Workbook and sheet definitions
- Table layouts (grids)
- Data binding expressions
- Control structures (loops)
- Positioning instructions
Example:
<Book name="Report">
<Sheet name="Data">
<Grid>
| Name | {{ .userName }} |
</Grid>
</Sheet>
</Book>
Data File
Data provides the values to inject into the template. Supported formats:
- JSON (
.json) - YAML (
.yaml,.yml)
Example:
{
"userName": "John Doe"
}
Generation Process
Template (.gxl) + Data (.json/.yaml) → goxcel → Excel File (.xlsx)
GXL Structure
Hierarchy
Book (Workbook)
└── Sheet (Worksheet)
├── Grid (Table)
├── For (Loop)
├── Anchor (Position)
└── Merge (Cell merge)
Book
The root element representing an Excel workbook:
<Book name="MyWorkbook">
<!-- Sheets go here -->
</Book>
Sheet
Represents a worksheet within the workbook:
<Sheet name="Sheet1">
<!-- Content goes here -->
</Sheet>
You can have multiple sheets:
<Book name="Report">
<Sheet name="Summary">
<!-- ... -->
</Sheet>
<Sheet name="Details">
<!-- ... -->
</Sheet>
</Book>
Grid
Defines a table using pipe-delimited syntax:
<Grid>
| Header1 | Header2 | Header3 |
| Value1 | Value2 | Value3 |
| Value4 | Value5 | Value6 |
</Grid>
Rules:
- Each row starts and ends with
| - Cells are separated by
| - Whitespace around values is trimmed
- Consistent column count per row recommended
Data Binding
Expressions
Use {{ }} to inject data:
<Grid>
| Name | {{ .name }} |
| Age | {{ .age }} |
</Grid>
With data:
{
"name": "Alice",
"age": 30
}
Nested Access
Use dot notation for nested data:
{{ .user.profile.email }}
With data:
{
"user": {
"profile": {
"email": "alice@example.com"
}
}
}
Array Access in Loops
<For each="item in items">
<Grid>
| {{ .item.name }} | {{ .item.value }} |
</Grid>
</For>
Type System
Automatic Type Inference
goxcel automatically detects types:
- Number:
123,45.67,-10 - Boolean:
true,false - Date:
2025-11-04,2025-11-04T10:30:00 - Formula:
=SUM(A1:A10) - String: Everything else
Type Hints
Force a specific type:
{{ .value:number }} <!-- Force as number -->
{{ .text:string }} <!-- Force as string -->
{{ .flag:boolean }} <!-- Force as boolean -->
{{ .created:date }} <!-- Force as date -->
Example:
<Grid>
| ID | {{ .id:string }} | <!-- "001" stays as text -->
| Amount | {{ .amount:number }} | <!-- Ensures numeric -->
</Grid>
Control Structures
For Loops
Iterate over arrays:
<For each="item in items">
<!-- This repeats for each item -->
<Grid>
| {{ .item.name }} |
</Grid>
</For>
Data:
{
"items": [
{"name": "Apple"},
{"name": "Banana"},
{"name": "Cherry"}
]
}
Output:
| Apple |
| Banana |
| Cherry |
Nested Loops
<For each="dept in departments">
<Grid>
| **{{ .dept.name }}** |
</Grid>
<For each="emp in dept.employees">
<Grid>
| {{ .emp.name }} | {{ .emp.role }} |
</Grid>
</For>
</For>
Positioning
Sequential (Default)
Content flows from current position:
<Grid>
| Row 1 |
</Grid>
<Grid>
| Row 2 | <!-- Appears below Row 1 -->
</Grid>
Absolute with Anchor
Set specific cell position:
<Anchor ref="A1" />
<Grid>
| Title |
</Grid>
<Anchor ref="A10" />
<Grid>
| Data starts here |
</Grid>
Grid with Ref
Position a grid at specific location:
<Grid ref="E5">
| Summary |
</Grid>
Styling
Markdown Syntax
Apply formatting within cells:
<Grid>
| **Bold text** |
| _Italic text_ |
| **_Bold and italic_** |
</Grid>
Supported:
**text**→ Bold_text_→ Italic
Formulas
Excel formulas work directly:
<Grid>
| 10 | 20 | =A1+B1 |
| =SUM(A1:A10) |
</Grid>
Cell Merging
Merge cells after defining them:
<Grid>
| Large Title |
</Grid>
<Merge range="A1:C1" />
Context Stack
When using loops, data context changes:
<!-- Root context -->
{{ .rootValue }}
<For each="item in items">
<!-- Item context (can still access root) -->
{{ .item.name }}
{{ .rootValue }} <!-- Still accessible -->
<For each="sub in item.subs">
<!-- Sub context (can access item and root) -->
{{ .sub.value }}
{{ .item.name }}
{{ .rootValue }}
</For>
</For>
Context Stack (innermost to outermost):
- Current loop variable (
.sub) - Parent loop variable (
.item) - Root data (
.rootValue)
Best Practices
Template Design
- Keep grids simple: One table per Grid tag
- Use anchors sparingly: Sequential flow is easier to maintain
- Name meaningfully: Clear sheet and workbook names
- Comment complex sections: Use XML comments
<!-- -->
Data Structure
- Match template paths: Ensure JSON structure matches template expressions
- Use arrays for loops: Structure data to match For loops
- Consistent types: Use same type for similar values
- Avoid deep nesting: Keep data structure reasonably flat
Type Management
- Use type hints for IDs: Force strings for numeric IDs like
001 - Explicit numbers: Use
:numberfor calculations - Date formats: Use ISO 8601 format:
YYYY-MM-DD - Boolean clarity: Use
true/falsenot"true"/"false"
Common Patterns
Header with Data Rows
<Grid>
| **Name** | **Email** | **Status** |
</Grid>
<For each="user in users">
<Grid>
| {{ .user.name }} | {{ .user.email }} | {{ .user.status }} |
</Grid>
</For>
Summary Section
<Anchor ref="A1" />
<Grid>
| **Report Summary** |
</Grid>
<Merge range="A1:C1" />
<Grid>
| Generated | {{ .date }} |
| Total Records | {{ .count:number }} |
</Grid>
Multi-Sheet Report
<Book name="MonthlyReport">
<Sheet name="Summary">
<Grid>
| **Total Sales** | {{ .total:number }} |
</Grid>
</Sheet>
<Sheet name="Details">
<For each="item in items">
<Grid>
| {{ .item.name }} | {{ .item.amount:number }} |
</Grid>
</For>
</Sheet>
</Book>
Next Steps
- Core Tags Reference - Complete tag documentation
- Control Structures - Loops and conditionals
- Expressions - Data binding details
- Examples - Real-world examples