retroxl

package module
v0.1.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 30, 2025 License: MIT Imports: 9 Imported by: 0

README

RetroXL — Legacy-Compatible XLS Generation for Modern Go Applications

RetroXL Logo

Go Reference Go Report Card

A pure-Go library for converting XLSX/CSV/TSV and in-memory data into legacy-compatible .xls files.

RetroXL is a lightweight Go library for generating legacy-compatible XLS files from modern spreadsheet data. It converts XLSX, CSV, TSV, and in-memory tabular structures into Excel-friendly .xls outputs — all without external binaries or system dependencies. RetroXL produces SpreadsheetML-based XLS files that open seamlessly in Excel and satisfy strict legacy upload systems such as banking portals. The API supports both file-path inputs and in-memory streams, allowing you to write directly to disk, return bytes in an API response, or upload to S3 like cloud storage — all from pure Go.

Repository: https://github.com/mhshajib/retroxl

Why RetroXL?

Many banking, government, and enterprise portals still refuse .xlsx files and only accept legacy .xls uploads. Generating real .xls files normally requires external tools like LibreOffice, Python, or Windows-only libraries.

RetroXL solves this by providing a pure-Go, dependency-free way to generate SpreadsheetML-based .xls files directly from your Go services — ideal for APIs, background jobs, cloud functions, or banking integrations.

Features

  • Pure-Go XLS generation (no LibreOffice, no Python, no system binaries)
  • Converts:
    • .xlsx.xls
    • .csv / .tsv.xls
    • in-memory tables ([][]any) → .xls
  • Generates SpreadsheetML-compatible .xls recognized by Excel
  • Supports:
    • file-path input/output
    • byte slice output ([]byte)
    • streaming output via io.Writer (HTTP, gRPC, S3)
  • Ideal for:
    • banking portals
    • government upload systems
    • legacy enterprise workflows

Supported Formats

Input Type Output
XLSX file XLS (SpreadsheetML 2003)
CSV / TSV XLS
In-memory data ([][]any) XLS
gRPC request XLS (bytes)
HTTP streaming XLS

Installation

go get github.com/mhshajib/retroxl

Basic usage

Convert an existing .xlsx file to .xls on disk
package main

import (
    "log"

    "github.com/mhshajib/retroxl"
)

func main() {
    if err := retroxl.ConvertXLSXToXLSFile("input.xlsx", "output.xls"); err != nil {
        log.Fatalf("convert failed: %v", err)
    }
}
Generate a bank upload file from in-memory data
package main

import (
    "log"

    "github.com/mhshajib/retroxl"
)

func main() {
    headers := []string{"AccountNo", "Amount", "Reference"}
    rows := [][]any{
        {"1234567890", 1200.50, "Invoice-2025-001"},
        {"0987654321", 300.00,  "Invoice-2025-002"},
    }

    sheet := retroxl.FromRows("BankUpload", headers, rows)

    if err := retroxl.WriteXLSFile("bank_upload.xls", []retroxl.Sheet{sheet}); err != nil {
        log.Fatalf("write xls failed: %v", err)
    }
}
Stream XLS content over HTTP
package main

import (
    "log"
    "net/http"

    "github.com/mhshajib/retroxl"
)

func bankHandler(w http.ResponseWriter, r *http.Request) {
    headers := []string{"AccountNo", "Amount", "Reference"}
    rows := [][]any{
        {"1234567890", 1200.50, "Invoice-2025-001"},
        {"0987654321", 300.00,  "Invoice-2025-002"},
    }

    sheet := retroxl.FromRows("BankUpload", headers, rows)

    w.Header().Set("Content-Type", "application/vnd.ms-excel")
    w.Header().Set("Content-Disposition", `attachment; filename="bank_upload.xls"`)

    if err := retroxl.WriteXLSWriter(w, []retroxl.Sheet{sheet}); err != nil {
        http.Error(w, "failed to generate xls", http.StatusInternalServerError)
        return
    }
}

func main() {
    http.HandleFunc("/bank-upload.xls", bankHandler)

    if err := http.ListenAndServe(":8080", nil); err != nil {
        log.Fatal(err)
    }
}
Convert any supported path to XLS bytes
data, err := retroxl.ConvertAnyToXLSBytes("input.xlsx")
if err != nil {
    // handle error
}

// data contains the XLS file content.
Convert a slice of structs to XLS
type Payment struct {
    AccountNo string
    Amount    float64
    Reference string
}

func main() {
    items := []Payment{
        {"1234567890", 1200.50, "Invoice-2025-001"},
        {"0987654321", 300.00,  "Invoice-2025-002"},
    }

    headers := []string{"AccountNo", "Amount", "Reference"}
    var rows [][]any
    for _, p := range items {
        rows = append(rows, []any{p.AccountNo, p.Amount, p.Reference})
    }

    sheet := retroxl.FromRows("BankUpload", headers, rows)
    _ = retroxl.WriteXLSFile("payments.xls", []retroxl.Sheet{sheet})
}

API Overview

All types and functions are documented with GoDoc comments.

Key pieces:

  • type Sheet – in-memory representation of a sheet
  • FromRows – build a Sheet from headers and rows
  • WriteXLSFile – write one or more sheets to a .xls file
  • WriteXLSBytes – generate XLS content as []byte
  • WriteXLSWriter – stream XLS content to any io.Writer
  • XLSXToSheets – read .xlsx from a path into []Sheet
  • CSVToSheets – read .csv/.tsv into []Sheet
  • PathToSheets – helper that dispatches by file extension
  • ConvertXLSXToXLSFile / ConvertXLSXToXLSBytes
  • ConvertAnyToXLSFile / ConvertAnyToXLSBytes

Limitations

  • The generated files are XML Spreadsheet 2003 wrapped in .xls. They are understood by Excel and many legacy systems that require .xls, but they are not BIFF8 binary workbooks.
  • retroxl focuses on simple tabular data:
    • values are written as strings, numbers, or booleans
    • advanced Excel features such as formulas, styles, and merged cells are not currently supported.

Contributing

Issues and pull requests are welcome at:

https://github.com/mhshajib/retroxl

Please include tests for any functional changes.

Contributors

Contributors

Contributors

License

RetroXL is licensed under the MIT License. See the full text in LICENSE.

Attribution is appreciated but not required. See RETROXL_ATTRIBUTION for optional attribution guidelines.


Documentation

Overview

Package retroxl is a pure-Go library for generating legacy-compatible XLS files from modern spreadsheet inputs. It converts XLSX, CSV, TSV, and in-memory tabular data into SpreadsheetML-based XLS files that open in Microsoft Excel and pass validation in legacy systems.

RetroXL is designed for integrations where banks, government portals, or older enterprise systems still require `.xls` uploads instead of modern `.xlsx`. The library has no external dependencies and does not rely on LibreOffice, Python, or system binaries.

The API supports converting files from disk or constructing sheets in memory. Output can be written directly to disk, returned as []byte, or streamed to any io.Writer (HTTP response, gRPC, S3 uploads, etc.).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ConvertAnyToXLSBytes

func ConvertAnyToXLSBytes(inPath string) ([]byte, error)

ConvertAnyToXLSBytes converts any supported source file on disk to XLS content returned as a byte slice.

func ConvertAnyToXLSFile

func ConvertAnyToXLSFile(inPath, outPath string) error

ConvertAnyToXLSFile converts any supported source file on disk to an .xls file on disk.

func ConvertXLSXToXLSBytes

func ConvertXLSXToXLSBytes(inPath string) ([]byte, error)

ConvertXLSXToXLSBytes converts an .xlsx file on disk to XLS content returned as a byte slice.

func ConvertXLSXToXLSFile

func ConvertXLSXToXLSFile(inPath, outPath string) error

ConvertXLSXToXLSFile converts an .xlsx file on disk to an .xls file on disk.

func WriteXLSBytes

func WriteXLSBytes(sheets []Sheet) ([]byte, error)

WriteXLSBytes writes one or more sheets and returns the XLS file content as a byte slice.

func WriteXLSFile

func WriteXLSFile(outPath string, sheets []Sheet) error

WriteXLSFile writes one or more sheets to a file path as XML Spreadsheet 2003 content with a .xls extension.

func WriteXLSWriter

func WriteXLSWriter(w io.Writer, sheets []Sheet) error

WriteXLSWriter writes one or more sheets to the provided io.Writer as XML Spreadsheet 2003 content.

Types

type Sheet

type Sheet struct {
	Name    string
	Headers []string
	Rows    [][]any
}

Sheet represents a single worksheet in a workbook. Headers are optional and, when present, are written as the first row. Each row must have the same length as Headers, if Headers are set.

func CSVToSheets

func CSVToSheets(path string, sep rune) ([]Sheet, error)

CSVToSheets reads a delimited text file (CSV or TSV) from the provided path and converts it into a single Sheet. The first row is treated as headers.

func FromRows

func FromRows(name string, headers []string, rows [][]any) Sheet

FromRows constructs a Sheet from a name, optional headers, and row data.

func PathToSheets

func PathToSheets(inPath string) ([]Sheet, error)

PathToSheets reads a file from disk and converts it into a slice of Sheet. The conversion is based on the file extension.

Supported extensions:

.xlsx
.csv
.tsv

func XLSXToSheets

func XLSXToSheets(path string) ([]Sheet, error)

XLSXToSheets reads an .xlsx file from the provided path and converts it into a slice of Sheet.

Directories

Path Synopsis
examples
http_stream command
slice_to_file command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL