Documentation
¶
Overview ¶
Package tabular provides explicit, bounded readers for tabular ingest.
CSV and configurable delimited input, fixed-width records, XLS, XLSX, and ZIP-backed sources share deterministic rows and typed errors. Parsers do not auto-detect formats or silently apply normalization. Callers choose the format, limits, header rules, and field transformations in configuration.
Delimited, fixed-width, ZIP entry, and XLSX row processing stream input. Legacy XLS workbooks are materialized up to MaxWorkbookBytes because the OLE2/BIFF8 format requires random access to workbook structures.
Index ¶
- func DecodeBytes(source []byte, sourceEncoding Encoding) (string, error)
- func DecodeReader(source io.Reader, sourceEncoding Encoding) (io.Reader, error)
- func ExtractBytes(record []byte, start, end int) ([]byte, error)
- type DelimitedConfig
- type DelimitedReader
- type Encoding
- type Error
- type ErrorKind
- type FixedWidthConfig
- type FixedWidthField
- type FixedWidthReader
- type HeaderCase
- type HeaderConfig
- type NormalizationConfig
- type Row
- type SpreadsheetCell
- type SpreadsheetConfig
- type SpreadsheetFormat
- type SpreadsheetReader
- type SpreadsheetRow
- type ZIPArchive
- type ZIPConfig
- type ZIPEntry
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DecodeBytes ¶
DecodeBytes validates and converts source bytes to UTF-8.
func DecodeReader ¶
DecodeReader returns a streaming UTF-8 view of source.
Types ¶
type DelimitedConfig ¶
type DelimitedConfig struct {
Delimiter rune
Comment rune
LazyQuotes bool
TrimLeadingSpace bool
AllowVariableFields bool
FieldsPerRecord int
// MaxRecordBytes bounds one logical record before parser allocation.
// Zero preserves the unbounded legacy behavior.
MaxRecordBytes int
// MaxFieldBytes bounds one parsed field before normalization.
// Zero preserves the unbounded legacy behavior.
MaxFieldBytes int
Header *HeaderConfig
Normalize NormalizationConfig
}
DelimitedConfig explicitly controls delimited-text parsing behavior.
type DelimitedReader ¶
type DelimitedReader struct {
// contains filtered or unexported fields
}
DelimitedReader streams records from CSV or another delimited text format.
func NewCSVReader ¶
func NewCSVReader(source io.Reader, config DelimitedConfig) (*DelimitedReader, error)
NewCSVReader constructs a comma-delimited streaming reader.
func NewDelimitedReader ¶
func NewDelimitedReader(source io.Reader, config DelimitedConfig) (*DelimitedReader, error)
NewDelimitedReader constructs a streaming reader for an explicit delimiter.
Example ¶
package main
import (
"fmt"
"strings"
tabular "github.com/faustbrian/golib/pkg/tabular"
)
func main() {
reader, err := tabular.NewDelimitedReader(strings.NewReader("name;city\nAda;Helsinki\n"), tabular.DelimitedConfig{
Delimiter: ';',
Header: &tabular.HeaderConfig{
Case: tabular.HeaderCaseLower,
RejectEmpty: true,
RejectDuplicates: true,
},
})
if err != nil {
panic(err)
}
header, err := reader.Header()
if err != nil {
panic(err)
}
row, err := reader.Read()
if err != nil {
panic(err)
}
fmt.Println(header)
fmt.Println(row)
}
Output: [name city] [Ada Helsinki]
func (*DelimitedReader) Header ¶
func (reader *DelimitedReader) Header() (Row, error)
Header returns the normalized first row when header handling is configured. The returned row is a copy and is safe for the caller to modify.
func (*DelimitedReader) Read ¶
func (reader *DelimitedReader) Read() (Row, error)
Read returns the next normalized record. io.EOF marks a clean end of input.
type Encoding ¶
type Encoding string
Encoding names a supported source character encoding.
const ( // EncodingUTF8 selects strict UTF-8 validation. EncodingUTF8 Encoding = "utf-8" // EncodingISO88591 selects the ISO-8859-1 single-byte encoding. EncodingISO88591 Encoding = "iso-8859-1" // EncodingWindows1252 selects the Windows-1252 single-byte encoding. EncodingWindows1252 Encoding = "windows-1252" )
type Error ¶
Error carries stable classification and optional ingest coordinates. Row and Field are one-based when set.
type ErrorKind ¶
type ErrorKind string
ErrorKind identifies a stable class of error that callers can match with errors.Is.
const ( // ErrorInvalidConfig indicates invalid parser configuration. ErrorInvalidConfig ErrorKind = "invalid configuration" // ErrorInvalidHeader indicates a missing or invalid header. ErrorInvalidHeader ErrorKind = "invalid header" // ErrorDuplicateHeader indicates a duplicate normalized header name. ErrorDuplicateHeader ErrorKind = "duplicate header" // ErrorMalformedRow indicates invalid record syntax or shape. ErrorMalformedRow ErrorKind = "malformed row" // ErrorInvalidEncoding indicates unsupported or invalid text encoding. ErrorInvalidEncoding ErrorKind = "invalid encoding" // ErrorInvalidLayout indicates an invalid fixed-width layout. ErrorInvalidLayout ErrorKind = "invalid fixed-width layout" // ErrorArchive indicates an invalid archive or entry. ErrorArchive ErrorKind = "archive error" // ErrorEntryNotFound indicates an absent exact archive entry name. ErrorEntryNotFound ErrorKind = "archive entry not found" // ErrorLimitExceeded indicates a configured resource limit was exceeded. ErrorLimitExceeded ErrorKind = "limit exceeded" // ErrorSpreadsheet indicates an invalid workbook or worksheet operation. ErrorSpreadsheet ErrorKind = "spreadsheet error" )
type FixedWidthConfig ¶
type FixedWidthConfig struct {
Fields []FixedWidthField
Encoding Encoding
AllowShortRecords bool
RejectTrailingBytes bool
MaxRecordBytes int
Normalize NormalizationConfig
}
FixedWidthConfig controls fixed-width record parsing.
type FixedWidthField ¶
FixedWidthField identifies a half-open byte range [Start, End) in a source record. Offsets apply before character decoding.
type FixedWidthReader ¶
type FixedWidthReader struct {
// contains filtered or unexported fields
}
FixedWidthReader streams newline-delimited fixed-width records.
func NewFixedWidthReader ¶
func NewFixedWidthReader(source io.Reader, config FixedWidthConfig) (*FixedWidthReader, error)
NewFixedWidthReader validates a layout and constructs a streaming reader.
Example ¶
package main
import (
"fmt"
"strings"
tabular "github.com/faustbrian/golib/pkg/tabular"
)
func main() {
reader, err := tabular.NewFixedWidthReader(strings.NewReader("001Ada Helsinki \n"), tabular.FixedWidthConfig{
Fields: []tabular.FixedWidthField{
{Name: "id", Start: 0, End: 3},
{Name: "name", Start: 3, End: 13, TrimSpace: true},
{Name: "city", Start: 13, End: 23, TrimSpace: true},
},
})
if err != nil {
panic(err)
}
row, err := reader.Read()
if err != nil {
panic(err)
}
fmt.Println(reader.Fields())
fmt.Println(row)
}
Output: [id name city] [001 Ada Helsinki]
func (*FixedWidthReader) Fields ¶
func (reader *FixedWidthReader) Fields() []string
Fields returns the configured field names in source order.
func (*FixedWidthReader) Read ¶
func (reader *FixedWidthReader) Read() (Row, error)
Read returns the next decoded row. io.EOF marks a clean end of input.
type HeaderCase ¶
type HeaderCase uint8
HeaderCase controls header-name case conversion.
const ( // HeaderCasePreserve retains source header casing. HeaderCasePreserve HeaderCase = iota // HeaderCaseLower converts headers to lowercase. HeaderCaseLower // HeaderCaseUpper converts headers to uppercase. HeaderCaseUpper )
type HeaderConfig ¶
type HeaderConfig struct {
TrimSpace bool
Case HeaderCase
Replace map[string]string
RejectEmpty bool
RejectDuplicates bool
}
HeaderConfig describes explicit header normalization and validation.
type NormalizationConfig ¶
NormalizationConfig describes explicit field-level data changes.
type Row ¶
type Row []string
Row is one tabular record. Fields retain source order.
func NormalizeHeader ¶
func NormalizeHeader(header Row, config HeaderConfig) (Row, error)
NormalizeHeader returns a normalized copy of header or a typed validation error. A UTF-8 BOM is removed from the first field before other changes.
func NormalizeRow ¶
func NormalizeRow(row Row, config NormalizationConfig) Row
NormalizeRow returns a copy of row with configured transformations applied.
type SpreadsheetCell ¶
type SpreadsheetCell struct {
// contains filtered or unexported fields
}
SpreadsheetCell is one immutable decoded worksheet cell.
func (SpreadsheetCell) Present ¶
func (cell SpreadsheetCell) Present() bool
Present reports whether the workbook stored a cell at this position.
func (SpreadsheetCell) Value ¶
func (cell SpreadsheetCell) Value() string
Value returns the decoded and normalized cell value.
type SpreadsheetConfig ¶
type SpreadsheetConfig struct {
Format SpreadsheetFormat
Sheet string
Header *HeaderConfig
Normalize NormalizationConfig
FieldsPerRecord int
AllowVariableFields bool
PreserveCellErrors bool
// PreserveCellPresence enables ReadCells and its absent-versus-stored-empty
// distinction. Zero preserves the optimized string-only Read behavior.
PreserveCellPresence bool
MaxWorkbookBytes int64
// MaxRecordBytes bounds one parsed worksheet row before normalization.
// Zero preserves the unbounded legacy behavior.
MaxRecordBytes int
// MaxFieldBytes bounds one parsed worksheet cell before normalization.
// Zero preserves the unbounded legacy behavior.
MaxFieldBytes int
// MaxSheets bounds the number of worksheets in an XLSX workbook.
// Zero preserves the unbounded legacy behavior.
MaxSheets int
ZIP ZIPConfig
}
SpreadsheetConfig controls workbook selection and row semantics.
type SpreadsheetFormat ¶
type SpreadsheetFormat string
SpreadsheetFormat identifies an explicitly selected workbook format.
const ( // FormatXLS selects legacy OLE2/BIFF8 workbooks. FormatXLS SpreadsheetFormat = "xls" // FormatXLSX selects OOXML workbooks. FormatXLSX SpreadsheetFormat = "xlsx" )
type SpreadsheetReader ¶
type SpreadsheetReader struct {
// contains filtered or unexported fields
}
SpreadsheetReader presents format-independent workbook rows.
func OpenSpreadsheet ¶
func OpenSpreadsheet(source io.ReaderAt, size int64, config SpreadsheetConfig) (*SpreadsheetReader, error)
OpenSpreadsheet opens an explicitly configured XLS or XLSX workbook.
func (*SpreadsheetReader) Close ¶
func (reader *SpreadsheetReader) Close() error
Close releases iterator resources. It does not close the caller's source.
func (*SpreadsheetReader) Header ¶
func (reader *SpreadsheetReader) Header() (Row, error)
Header returns a normalized copy of the configured first row.
func (*SpreadsheetReader) Read ¶
func (reader *SpreadsheetReader) Read() (Row, error)
Read returns the next worksheet row.
func (*SpreadsheetReader) ReadCells ¶
func (reader *SpreadsheetReader) ReadCells() (SpreadsheetRow, error)
ReadCells returns the next worksheet row while preserving whether each cell was stored or absent. Values follow the same normalization and error policy as Read.
type SpreadsheetRow ¶
type SpreadsheetRow []SpreadsheetCell
SpreadsheetRow preserves workbook cell presence alongside decoded values.
type ZIPArchive ¶
type ZIPArchive struct {
// contains filtered or unexported fields
}
ZIPArchive is a validated, indexed ZIP source.
func (*ZIPArchive) Entries ¶
func (archive *ZIPArchive) Entries() []ZIPEntry
Entries returns archive metadata in the original central-directory order.
func (*ZIPArchive) Extract ¶
func (archive *ZIPArchive) Extract(name string, destination io.Writer) error
Extract streams one exact entry to destination and verifies its ZIP checksum.
func (*ZIPArchive) Open ¶
func (archive *ZIPArchive) Open(name string) (io.ReadCloser, error)
Open returns a streaming reader for an exact, non-directory entry name.
type ZIPConfig ¶
type ZIPConfig struct {
MaxEntries int
MaxEntryBytes uint64
MaxTotalBytes uint64
MaxCompressionRatio uint64
RejectSymlinks bool
}
ZIPConfig defines archive-bomb safeguards. Zero size values select documented finite defaults. A zero compression ratio and false link policy preserve the prior behavior.