A template-based Excel generation library and CLI tool for Go
goxcel transforms human-readable .gxl templates into Excel .xlsx files using a simple, grid-oriented syntax. No external dependencies required.
⚠️ Development Status
This project is currently under active development. Breaking changes may occur between versions until v1.0.0 is released. Please use with caution in production environments.
- 📝 Template-First: Write Excel layouts in readable text format
- 🎯 Grid-Oriented: Natural pipe-delimited table syntax
- 🔄 Data-Driven: Separate templates from data with JSON context
- 🎨 Feature-Rich: Formulas, loops, merges, images, charts, and more
- 🚀 Pure Go: No external XLSX libraries or dependencies
- 📊 Production-Ready: Clean architecture with structured logging
Template (.gxl):
<Book>
<Sheet name="Invoice">
<Grid>
| Invoice #{{invoiceNumber}} |
| Customer: {{customer}} |
</Grid>
<Grid>
| Item | Quantity | Price |
</Grid>
<For src="items">
<Grid>
| {{name}} | {{qty}} | ${{price}} |
</Grid>
</For>
</Sheet>
</Book>Data (JSON):
{
"invoiceNumber": "INV-001",
"customer": "Acme Corp",
"items": [
{"name": "Widget", "qty": 10, "price": 50.00},
{"name": "Gadget", "qty": 5, "price": 120.00}
]
}Result: Professional Excel file with dynamic data populated.
- ✅ Template-based generation with
.gxlformat - ✅ Grid syntax with pipe-delimited tables
- ✅ Variable interpolation with
{{ expr }}syntax - ✅ Cell type inference: Automatic detection of numbers, formulas, booleans, dates
- ✅ Type hints: Explicit type control with
{{ value:type }}syntax - ✅ Control structures:
<For>loops (v1.0),<If>conditionals (planned v1.1) - ✅ Excel formulas with cell references
- ✅ Cell merging for headers and layouts
- ✅ Multi-sheet workbooks with independent sheets
- ✅ JSON and YAML data: Support for both data formats
- ⏳ Images: PNG/JPEG embedding
- ⏳ Shapes: Rectangles, ellipses, arrows
- ⏳ Charts: Column, bar, line, pie charts
- ⏳ Pivot tables: Dynamic data aggregation
- ✅ Pure Go: No C dependencies, easy deployment
- ✅ CLI tool: Generate files from command line
- ✅ Library API: Use as Go package in your code
- ✅ Structured logging: Message codes for traceability
- ✅ Clean architecture: Testable, maintainable code
go install github.com/ryo-arima/goxcel/cmd@latestgo get github.com/ryo-arima/goxcel# Build from source
make build
# Generate Excel file from JSON data
.bin/goxcel generate --template .etc/sample.gxl --data .etc/sample.json --output invoice.xlsx
# Generate Excel file from YAML data
.bin/goxcel generate --template .etc/sample.gxl --data .etc/sample.yaml --output invoice.xlsx
# Preview without generating file
.bin/goxcel generate --template .etc/sample.gxl --data .etc/sample.json --dry-run
# Format a GXL template (pretty-print)
.bin/goxcel format .etc/sample.gxl # prints to stdout
.bin/goxcel format -w .etc/sample.gxl # in-place overwrite
.bin/goxcel format -o .etc/sample.formatted.gxl .etc/sample.gxl
# Formatting behavior:
# - Removes double blank lines outside Grid content
# - Inlines empty tags: <Tag ...> </Tag> becomes a single line
# - Aligns pipe columns inside <Grid> so '|' line up
# - Preserves non-whitespace text and XML commentspackage main
import (
"github.com/ryo-arima/goxcel/pkg/config"
"github.com/ryo-arima/goxcel/pkg/controller"
)
func main() {
cfg := config.NewBaseConfig()
ctrl := controller.NewCommonController(cfg)
err := ctrl.Generate(
".etc/sample.gxl",
".etc/sample.json",
"output.xlsx",
false, // dry-run
)
if err != nil {
panic(err)
}
}📚 Comprehensive documentation available at docs/
Build and view locally:
make docs-build
make docs-serve
# Open http://localhost:3000- GXL Specification - Complete format reference
- Getting Started Guide - Tutorials and examples
- API Reference - Go package documentation
- Vision & Strategy - Project roadmap
Book and Sheets
<Book>
<Sheet name="Sheet1">
<!-- Sheet content -->
</Sheet>
<Sheet name="Sheet2">
<!-- Another sheet -->
</Sheet>
</Book>Grid Tables (Pipe-delimited)
<Grid>
| Header 1 | Header 2 | Header 3 |
| Value 1 | Value 2 | Value 3 |
| Data A | Data B | Data C |
</Grid>Grid with Absolute Position (v1.0+)
<!-- Normal sequential grid -->
<Grid>
| Main Content |
</Grid>
<!-- Absolute position at E1 (doesn't affect cursor) -->
<Grid ref="E1">
| Side Note |
</Grid>
<!-- Continues after first grid -->
<Grid>
| More Content |
</Grid>Variable Interpolation
<Grid>
| Customer: {{customer.name}} |
| Date: {{invoice.date}} |
| Total: ${{invoice.total}} |
</Grid>Loops (Iterate over arrays)
<For src="items">
<Grid>
| {{name}} | {{quantity}} | {{price}} |
</Grid>
</For>Loop Variables
<For src="items">
<Grid>
| Row {{_number}} | {{name}} | =B{{_startRow}}*2 |
</Grid>
</For>{{_index}}- Zero-based index (0, 1, 2, ...){{_number}}- One-based number (1, 2, 3, ...){{_startRow}}- Excel row number for current iteration{{_endRow}}- Last row number (available after loop)
Cell Merging
<Grid>
| Title spanning multiple columns | | | |
</Grid>
<Merge range="A1:D1" />Positioning with Anchor
<Anchor cell="E1">
<Grid>
| Side content |
</Grid>
</Anchor>Excel Formulas
<Grid>
| =SUM(A1:A10) |
| =AVERAGE(B:B) |
| =IF(C1>100,"High","Low") |
</Grid>Cell Types and Type Hints (v1.0+)
GXL automatically infers cell types, but you can use type hints for explicit control:
<Grid>
| Type | Auto-detected | With Type Hint |
| Number | {{ 42 }} | {{ .quantity:int }} |
| Float | {{ 3.14 }} | {{ .price:float }} |
| Boolean | {{ true }} | {{ .enabled:bool }} |
| Date | {{ "2025-11-03" }} | {{ .timestamp:date }} |
| Formula | =SUM(A1:A10) | =AVERAGE(B:B) |
| String | {{ "Hello" }} | {{ .zipCode:string }} |
</Grid>Type Inference Rules:
- Values starting with
=→ Formula true/false→ Boolean- Numeric patterns → Number
- ISO date format → Date
- Everything else → String
Available Type Hints:
:int,:float,:number- Numeric values:bool,:boolean- Boolean values:date- Date values:string- Force text (useful for zip codes, IDs)
Literal Values:
<Grid>
| {{ "Text" }} | String literal |
| {{ 123 }} | Number literal |
| {{ true }} | Boolean literal |
</Grid>Images
<Image src="logo.png" cell="E1" width="100" height="50" />Shapes
<Shape kind="rectangle" cell="E5" text="Note" width="150" height="40" />Charts
<Chart type="column" cell="E8" dataRange="A3:C10" title="Sales" width="420" height="240" />Pivot Tables
<Pivot cell="E15" sourceRange="A3:C100" rows="Category" values="SUM:Amount" />goxcel/
├── .bin/ # Built binaries
├── .etc/ # Configuration and sample files
│ ├── sample.gxl # Sample GXL template
│ └── sample.json # Sample data
├── cmd/ # CLI entry point
│ └── main.go
├── docs/ # Documentation (mdbook)
│ ├── book.toml # Configuration
│ ├── dist/ # Built HTML (gitignored)
│ └── src/ # Markdown sources
│ ├── specification/ # GXL format specification
│ ├── reference/ # API reference
│ └── guide/ # User guides
├── pkg/ # Application packages
│ ├── command.go # CLI commands
│ ├── config/ # Configuration layer
│ ├── controller/ # Command handlers (CLI interface)
│ ├── model/ # Data structures
│ │ ├── gxl.go # GXL AST
│ │ └── xlsx.go # XLSX models
│ ├── repository/ # File I/O
│ │ ├── gxl.go # GXL parser
│ │ └── xlsx.go # XLSX writer
│ ├── usecase/ # Business logic
│ │ ├── book.go # Book rendering
│ │ ├── cell.go # Cell processing
│ │ └── sheet.go # Sheet rendering
│ └── util/ # Utilities
│ └── logger.go # Structured logging
├── go.mod
├── Makefile # Build tasks
└── README.md
1. Config Layer: Dependency injection and configuration 2. Controller Layer: CLI commands and handlers 3. UseCase Layer: Core business logic (template rendering) 4. Repository Layer: File I/O (GXL parsing, XLSX writing) 5. Model Layer: Data structures (GXL AST, XLSX models)
.gxl Template + JSON Data
↓
[Parser]
↓
GXL AST
↓
[Renderer] ← JSON Context
↓
XLSX Model (Book → Sheets → Cells)
↓
[XLSX Writer]
↓
.xlsx File (ZIP containing XML files)
XLSX files are ZIP archives containing XML files:
output.xlsx (ZIP)
├── [Content_Types].xml # MIME types
├── _rels/
│ └── .rels # Package relationships
└── xl/
├── workbook.xml # Workbook structure
├── worksheets/
│ ├── sheet1.xml # Sheet data
│ └── sheet2.xml
├── styles.xml # Styles and formats
└── sharedStrings.xml # Shared string table
- Parse Phase: Read
.gxlfile → Build AST - Render Phase: Walk AST + Evaluate expressions → Generate cells
- Write Phase: Marshal XML → Create ZIP → Write
.xlsx
// Define XLSX structure with XML tags
type Worksheet struct {
XMLName xml.Name `xml:"http://... worksheet"`
SheetData SheetData `xml:"sheetData"`
}
// Marshal to XML
xml.MarshalIndent(worksheet, "", " ")- Go 1.21+
- mdbook (for documentation):
cargo install mdbook
# Build CLI
make build
# Run with sample
make run
# Dry run (preview)
make run-dry
# Run tests
make test
# Build documentation
make docs-build
# Serve documentation
make docs-serve
# Clean build artifacts
make cleanGenerate monthly/quarterly reports with dynamic data from databases or APIs.
Create professional invoices, quotes, and contracts with consistent formatting.
Export application data to Excel with custom layouts and formulas.
Generate hundreds of personalized Excel files from templates.
Populate Excel forms with data from web services or user input.
Typical Performance (M1 Mac, Go 1.21):
- Small template (10 sheets, 100 rows): ~50ms
- Medium template (100 sheets, 1000 rows): ~500ms
- Large template (1000 rows with loops): ~2s
Memory Usage:
- Lightweight: ~10MB for typical templates
- Scales linearly with data size
| Feature | goxcel | excelize | xlsx | Apache POI |
|---|---|---|---|---|
| Template-based | ✅ | ❌ | ❌ | ❌ |
| Pure Go | ✅ | ✅ | ✅ | ❌ (Java) |
| No dependencies | ✅ | ❌ | ❌ | ❌ |
| Grid syntax | ✅ | ❌ | ❌ | ❌ |
| CLI tool | ✅ | ❌ | ❌ | ❌ |
| Data-driven | ✅ |
We welcome contributions! Here's how to get started:
git clone https://github.com/yourusername/goxcel.git
cd goxcelgit checkout -b feature/my-feature- Follow Go best practices
- Add tests for new features
- Update documentation
- Run tests:
make test
- Clear description of changes
- Reference related issues
- Ensure CI passes
- Code Style: Follow Go conventions (
gofmt,golint) - Testing: Unit tests for all new code
- Documentation: Update docs for user-facing changes
- Commits: Clear, descriptive commit messages
- 🐛 Bug fixes
- 📝 Documentation improvements
- ✨ New features (check roadmap)
- 🧪 Test coverage
- 🌍 Internationalization
- 📊 Performance optimizations
See FAQ for more questions.
This project is licensed under the MIT License - see the LICENSE file for details.
- Excel specification: Office Open XML Standard
- Go community forexcellent tools and libraries
- GitHub Issues: Report bugs or request features
- Discussions: Ask questions and share ideas
⭐ If you find goxcel useful, please star the repository!