xls

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Apr 21, 2026 License: MIT Imports: 12 Imported by: 0

README

go-xls

CI Go Reference Go Latest Release

Small, io.Writer / io.Reader–first helpers for tabular data: UTF‑16LE CSV (BOM + sep=), legacy binary .xls (linear BIFF), .xlsx via excelize, GitHub-style markdown pipe tables, and optional HTTP attachment headers.

Install

go get github.com/eSlider/go-xls@v1.0.0

The string xls.Version matches this release (1.0.0). Git tags use a v prefix (v1.0.0); keep the const and tag in sync when publishing.

Write legacy .xls

tab := xls.Table{
	Columns: []string{"name", "qty"},
	Rows:    [][]string{{"apple", "3"}},
}
var buf bytes.Buffer
if err := xls.WriteXLS(&buf, tab, true); err != nil {
	log.Fatal(err)
}

Read legacy .xls

Linear BIFF only (BOF 0x809, string 0x204, number 0x203, EOF 0x0A). OLE compound workbooks (D0 CF 11 E0 …) return xls.ErrOLEWorkbook — use another reader or convert to .xlsx.

tab, err := xls.ReadXLS(bytes.NewReader(buf.Bytes()), true)
if err != nil {
	log.Fatal(err)
}
maps, err := xls.ReadXLSToMaps(bytes.NewReader(buf.Bytes()))
_ = maps

Write UTF‑16LE CSV

var out bytes.Buffer
err := xls.WriteCSV(&out, tab, ",", `"`, "UTF-8", true)

Write .xlsx

var out bytes.Buffer
if err := xls.WriteXLSX(&out, tab, true); err != nil {
	log.Fatal(err)
}

Markdown pipe tables

var md bytes.Buffer
if err := xls.WriteMarkdownTable(&md, tab); err != nil {
	log.Fatal(err)
}
parsed, err := xls.ReadMarkdownTable(bytes.NewReader(md.Bytes()))
_, _, err = xls.ReadMarkdownTableDetailed(bytes.NewReader(md.Bytes()))
_ = parsed

Alignment round-trip: WriteMarkdownTableWith + ReadMarkdownTableDetailed + MarkdownMarshalOpts{Align: …}.

HTTP attachment

(bytes and net/http imports omitted.)

body := bytes.NewReader(buf.Bytes())
if err := xls.WriteAttachment(w, "export.xls", xls.ContentTypeXLS, body, int64(buf.Len()), true); err != nil {
	log.Fatal(err)
}

Use size < 0 to omit Content-Length (chunked transfer).

Behaviour notes

  • Table: if Columns is empty, names "0", "1", … are derived from the widest row.
  • .xls strings: ISO‑8859‑1 bytes; unmappable runes become ?. Numeric-looking cells use strconv.ParseFloat on trimmed text.
  • CSV: only UTF‑8 source → UTF‑16LE is implemented for encodingFrom today.
  • Markdown: | and \ in cells are escaped; pipe tables follow common GitHub-style divider rules.

Testing

go test -v -race ./...

License

MIT

Documentation

Index

Constants

View Source
const (
	TypeCSV  = "csv"
	TypeXLS  = "xls"
	TypeXLSX = "xlsx"
)

Format identifiers for helpers and documentation.

View Source
const (
	XLSIntType    = 0x203
	XLSStringType = 0x204
)

BIFF legacy cell record types (binary .xls subset).

View Source
const (
	ContentTypeCSV  = "text/csv;charset=UTF-16LE"
	ContentTypeXLS  = "application/vnd.ms-excel"
	ContentTypeXLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
)

MIME-style content types for tabular downloads.

View Source
const Version = "1.0.0"

Version is the release version of this module (semantic versioning). Keep it in sync with the git tag when publishing (e.g. tag v1.0.0 → Version "1.0.0").

Variables

View Source
var (
	// ErrOLEWorkbook means the input is an OLE compound document (.xls as produced by Excel 97).
	// [ReadXLS] only supports the linear BIFF stream from [WriteXLS]; use another tool or convert to .xlsx.
	ErrOLEWorkbook = errors.New("xls: OLE compound workbook not supported (linear BIFF stream only)")
	// ErrTruncatedXLS means the stream ended inside a BIFF record.
	ErrTruncatedXLS = errors.New("xls: truncated record")
)

Functions

func DisableDownloadHeaders

func DisableDownloadHeaders(h http.Header)

DisableDownloadHeaders removes cache headers added by EnableDownloadHeaders.

func EnableDownloadHeaders

func EnableDownloadHeaders(h http.Header)

EnableDownloadHeaders sets Cache-Control, Pragma, and Expires for attachment responses.

func ReadMarkdownTableDetailed added in v1.0.0

func ReadMarkdownTableDetailed(r io.Reader) (Table, []MarkdownAlign, error)

ReadMarkdownTableDetailed is like ReadMarkdownTable but also returns column alignment from the divider row (for round-tripping with WriteMarkdownTableWith).

func ReadXLSToMaps added in v1.0.0

func ReadXLSToMaps(r io.Reader) ([]map[string]string, error)

ReadXLSToMaps reads r like ReadXLS with a header row and returns one map per data row. Duplicate header names: later columns overwrite earlier keys in each map.

func TrimTrailingFinalNewline

func TrimTrailingFinalNewline(b []byte) []byte

TrimTrailingFinalNewline removes one trailing UTF-16LE newline (after BOM) from b if present.

func WriteAttachment

func WriteAttachment(w http.ResponseWriter, fileName, contentType string, body io.Reader, size int64, enableDownload bool) error

WriteAttachment sets Content-Type, Content-Disposition, optional Content-Length, optional download cache headers, then copies body into w.

If size >= 0, Content-Length is set to size. If size < 0, Content-Length is omitted (chunked transfer).

func WriteCSV added in v1.0.0

func WriteCSV(w io.Writer, tab Table, delimiter, enclosure string, encodingFrom string, detectHead bool) error

WriteCSV writes UTF-16LE CSV with a BOM and a leading sep= line. Cell text must be UTF-8; encodingFrom is reserved (only UTF-8 is supported today).

func WriteMarkdownTable added in v1.0.0

func WriteMarkdownTable(w io.Writer, tab Table) error

WriteMarkdownTable writes a GitHub-flavored markdown pipe table to w. The header row uses Table.Columns (after [normalizeTable] if columns were empty).

func WriteMarkdownTableWith added in v1.0.0

func WriteMarkdownTableWith(w io.Writer, tab Table, opts MarkdownMarshalOpts) error

WriteMarkdownTableWith writes a markdown pipe table to w with optional column alignment.

func WriteXLS added in v1.0.0

func WriteXLS(w io.Writer, tab Table, detectHead bool) error

WriteXLS writes a legacy binary .xls workbook as a linear little-endian BIFF record stream (BOF 0x809, LABEL-style strings 0x204, IEEE doubles 0x203, EOF 0x0A). It is not an OLE compound file.

func WriteXLSX added in v1.0.0

func WriteXLSX(w io.Writer, tab Table, detectHead bool) error

WriteXLSX writes a single-sheet OpenXML .xlsx workbook to w.

Types

type MarkdownAlign added in v1.0.0

type MarkdownAlign int

MarkdownAlign is column alignment in a GitHub-style pipe table divider row.

const (
	AlignLeft MarkdownAlign = iota
	AlignCenter
	AlignRight
)

type MarkdownMarshalOpts added in v1.0.0

type MarkdownMarshalOpts struct {
	// Align is per-column alignment (shorter slice defaults remaining columns to left).
	Align []MarkdownAlign
}

MarkdownMarshalOpts controls markdown table output from WriteMarkdownTableWith.

type Table

type Table struct {
	Columns []string
	Rows    [][]string
}

Table is column-ordered tabular data. Columns defines order and names; each Rows[i] may be shorter than len(Columns) (missing cells are empty). If Columns is nil or empty, synthetic names "0","1",… are derived from the widest row.

func ReadMarkdownTable added in v1.0.0

func ReadMarkdownTable(r io.Reader) (Table, error)

ReadMarkdownTable parses the first GitHub-style pipe table from r (header + divider + body rows). Prose before the first header+divider pair is skipped.

func ReadXLS added in v1.0.0

func ReadXLS(r io.Reader, firstRowAsHeader bool) (Table, error)

ReadXLS reads a legacy .xls linear BIFF stream from r. It is not a full OLE workbook parser; inputs starting with the OLE signature return ErrOLEWorkbook.

When firstRowAsHeader is true, row 0 becomes Table.Columns and following rows Table.Rows. When false, columns are named "0","1",… (widest row) and every grid row is in Table.Rows.

Jump to

Keyboard shortcuts

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