csvstruct

package module
v0.0.0-...-8511ca9 Latest Latest
Warning

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

Go to latest
Published: Aug 9, 2024 License: BSD-3-Clause Imports: 7 Imported by: 0

README

csvstruct

PkgGoDev

Import multiply-typed structured data from CSV to Go types.

Import spreadsheets:

screenshot

Into Go types:

type Info struct {
  Name string
  Class string
}

type Attributes struct {
  HP int
  Damage int
}

type Prefab struct {
  Info *Info
  Attributes *Attributes
}

Get typed data:

Prefab{Info{"Alex", "Fighter"}, Attributes{100, 10}}
Prefab{Info{"Mary", "Queen"}, nil}
Prefab{Info{"Jayden", "Wizard"}, Attributes{90, 20}}

When working with Google Sheets or Microsoft Excel, export data to CSV and import it to your program using the csvstruct library.

Example

Let's assume the following CSS file:

Info.Name,Info.Class,Attributes.HP,Attributes.Damage
Alex,Fighter,100,10
Jayden,Wizard,90,20
Mary,Queen,,
...

The following program uses csvstruct library to import the data above:

type Info struct {
    Name  string
    Class string
}

type Attributes struct {
    HP     int
    Damage int
}

type Prefab struct {
    Info       *Info
    Attributes *Attributes
}

reader := csvstruct.NewReader[Prefab](csv.NewReader(strings.NewReader(testData)))

var prefab Prefab
for {
    err := reader.Read(&prefab)
    if err == io.EOF {
        break
    }
    if err != nil {
        panic(err)
    }

    fmt.Printf("%v\n", prefab.Info)
    fmt.Printf("%v\n", prefab.Attributes)
}

Format

The CSV data must have the following format:

Header

The first row of the CSV data is the header and it must be present.

Each header column contains the name of a component followed by a period . and an optional field name, e.g., MyComponent.MyField.

The MyComponent.MyField must be valid, i.e., MyComponent must be a valid field name of the type T passed to NewReader, and MyField must be a valid field of MyComponent.

If a cell is not given, then it's field is default initialized according to the default initialization of Go. For example, pointers are default initialized to nil and value types are default initialized to 0, empty structs, empty arrays, etc.

It's not required to put in the CSV header all the fields of MyComponent. Rather, only the fields that should be imported by those CSV data are present.

Data rows

The rows that follow a CSV header are data rows.

The CSV data can contain 0 or more data rows.

The data rows must contain in each cell data that is compatible with the type of the field specified in the CSV header.

For example, a field of type string can contain either an empty or non-empty cell (without quotes) since that is compatible with the string type.

A field of type Int can either an empty or non-empty cell containing a numerical value.

Empty cells default initialize fields according to Go semantics.

Multiple tables in the same CSV

It's possible to have multiple "tables" in the same CSV file. Tables are separate by CSV header rows. The library caller must be able to determine when a new CSV header is about to come up as the next row. In this case, the caller can use Reader.Clear to start a new table of CSV data, followed by Reader.Read to parse the new table.

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Reader

type Reader[T any] struct {
	// contains filtered or unexported fields
}

Reader parses component data from CSV data.

This is thread compatible, i.e., it's safe for non-concurrent use and it can be combined with external synchronization so it can be called concurrently.

Example
package main

import (
	"encoding/csv"
	"fmt"
	"io"
	"strings"

	"github.com/jabolopes/csvstruct"
)

const testData = `Info.Name,Info.Class,Attributes.HP,Attributes.Damage,Player
Alex,Fighter,100,10,
Jayden,Wizard,90,20,
Mary,Queen,,,
Player,,,,0
`

type Info struct {
	Name  string
	Class string
}

type Attributes struct {
	HP     int
	Damage int
}

type Player struct{}

type Prefab struct {
	Info       *Info
	Attributes *Attributes
	Player     *Player
}

func main() {
	reader := csvstruct.NewReader[Prefab](csv.NewReader(strings.NewReader(testData)))

	var prefab Prefab
	for {
		err := reader.Read(&prefab)
		if err == io.EOF {
			break
		}
		if err != nil {
			panic(err)
		}

		fmt.Printf("%#v\n", prefab.Info)
		fmt.Printf("%#v\n", prefab.Attributes)
		fmt.Printf("%#v\n", prefab.Player)
	}

}
Output:

&csvstruct_test.Info{Name:"Alex", Class:"Fighter"}
&csvstruct_test.Attributes{HP:100, Damage:10}
(*csvstruct_test.Player)(nil)
&csvstruct_test.Info{Name:"Jayden", Class:"Wizard"}
&csvstruct_test.Attributes{HP:90, Damage:20}
(*csvstruct_test.Player)(nil)
&csvstruct_test.Info{Name:"Mary", Class:"Queen"}
(*csvstruct_test.Attributes)(nil)
(*csvstruct_test.Player)(nil)
&csvstruct_test.Info{Name:"Player", Class:""}
(*csvstruct_test.Attributes)(nil)
&csvstruct_test.Player{}

func NewReader

func NewReader[T any](reader *csv.Reader) *Reader[T]

NewReader returns a new reader using the given `reader` as the underlying CSV reader. The type `T` is the schema that is used to parse the data.

func (*Reader[T]) Clear

func (r *Reader[T]) Clear()

Clears part of the internal state so that this is ready to continue parsing, namely, it clears the permanent error and all the internal descriptors. After Clear() is called, Read() will expect the next row to be a CSV header. This is useful if the same CSV file contains multiple tables of data.

func (*Reader[T]) Read

func (r *Reader[T]) Read(t *T) error

Reads the next CSV row and returns typed data.

It's expected that the first row is the CSV header. This header is used to construct the column descriptors that will be used to direct column parsing.

If Clear() has been called, reading can resume and it's once again expected that the next row is a CSV header row.

Returns io.EOF when the end of file is reached. When an error is returned, the first return value is always nil. In other words, this either returns valid data or it returns an error, but never both simultaneously.

Jump to

Keyboard shortcuts

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