Skip to content

An Excel (.xlsx) generation library for Go. It parses grid-oriented .gxl templates and produces .xlsx files without external dependencies.

License

Notifications You must be signed in to change notification settings

ryo-arima/goxcel

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

goxcel

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.

Why goxcel?

  • 📝 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

Quick Example

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.

Features

Core Features

  • Template-based generation with .gxl format
  • 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

Components (Placeholders in v1.0)

  • Images: PNG/JPEG embedding
  • Shapes: Rectangles, ellipses, arrows
  • Charts: Column, bar, line, pie charts
  • Pivot tables: Dynamic data aggregation

Developer Experience

  • 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

Installation

Install CLI Tool

go install github.com/ryo-arima/goxcel/cmd@latest

Use as Library

go get github.com/ryo-arima/goxcel

Quick Start

Using the CLI

# 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 comments

Using as Library

package 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)
    }
}

Documentation

📚 Comprehensive documentation available at docs/

Build and view locally:

make docs-build
make docs-serve
# Open http://localhost:3000

Key Documentation

GXL Template Language

Core Syntax

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>

Component Syntax (v1.0: Placeholders)

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" />

Architecture

Project Structure

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

Clean Architecture Layers

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)

Data Flow

.gxl Template + JSON Data
        ↓
    [Parser]
        ↓
    GXL AST
        ↓
   [Renderer] ← JSON Context
        ↓
  XLSX Model (Book → Sheets → Cells)
        ↓
  [XLSX Writer]
        ↓
.xlsx File (ZIP containing XML files)

How It Works

XLSX File Structure

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

Generation Process

  1. Parse Phase: Read .gxl file → Build AST
  2. Render Phase: Walk AST + Evaluate expressions → Generate cells
  3. Write Phase: Marshal XML → Create ZIP → Write .xlsx

Type-Safe XML Generation

// 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, "", "  ")

Development

Prerequisites

  • Go 1.21+
  • mdbook (for documentation): cargo install mdbook

Makefile Commands

# 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 clean

Use Cases

📊 Business Reports

Generate monthly/quarterly reports with dynamic data from databases or APIs.

📋 Invoices & Documents

Create professional invoices, quotes, and contracts with consistent formatting.

📈 Data Exports

Export application data to Excel with custom layouts and formulas.

🏢 Batch Processing

Generate hundreds of personalized Excel files from templates.

📑 Form Filling

Populate Excel forms with data from web services or user input.

Performance

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

Comparison with Other Tools

Feature goxcel excelize xlsx Apache POI
Template-based
Pure Go ❌ (Java)
No dependencies
Grid syntax
CLI tool
Data-driven ⚠️ Manual ⚠️ Manual ⚠️ Manual

Contributing

We welcome contributions! Here's how to get started:

1. Fork and Clone

git clone https://github.com/yourusername/goxcel.git
cd goxcel

2. Create a Branch

git checkout -b feature/my-feature

3. Make Changes

  • Follow Go best practices
  • Add tests for new features
  • Update documentation
  • Run tests: make test

4. Submit Pull Request

  • Clear description of changes
  • Reference related issues
  • Ensure CI passes

Development Guidelines

  • 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

Areas for Contribution

  • 🐛 Bug fixes
  • 📝 Documentation improvements
  • ✨ New features (check roadmap)
  • 🧪 Test coverage
  • 🌍 Internationalization
  • 📊 Performance optimizations

FAQ

See FAQ for more questions.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

Contact & Support


⭐ If you find goxcel useful, please star the repository!

About

An Excel (.xlsx) generation library for Go. It parses grid-oriented .gxl templates and produces .xlsx files without external dependencies.

Topics

Resources

License

Stars

Watchers

Forks