Skip to content

Instantly share code, notes, and snippets.

@owulveryck
Last active March 10, 2017 13:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save owulveryck/0fc68c90fa4875647b54f62e2066707d to your computer and use it in GitHub Desktop.
Save owulveryck/0fc68c90fa4875647b54f62e2066707d to your computer and use it in GitHub Desktop.
Decoding a csv to an object in GO
package main
import (
"encoding/csv"
"io"
"reflect"
)
// test holds a structure
type test struct {
ID string `csv:"myid"`
Name string `csv:"prenom"`
Last string `csv:"nom"`
Test string `csv:"nonexitent"`
}
type ret struct {
V test
Err error
}
// parse a csv file and return an array of resources
func parse(r io.Reader) chan ret {
c := make(chan ret, 0)
go func() {
defer close(c)
rd := csv.NewReader(r)
var header []string
header, err := rd.Read()
if err != nil {
c <- ret{test{}, err}
}
e := test{}
et := reflect.TypeOf(e)
var headers = make(map[string]int, et.NumField())
for i := 0; i < et.NumField(); i++ {
headers[et.Field(i).Name] = func(element string, array []string) int {
for k, v := range array {
if v == element {
return k
}
}
return -1
}(et.Field(i).Tag.Get("csv"), header)
}
for {
var e = test{}
record, err := rd.Read()
if err == io.EOF {
break
}
if err != nil {
c <- ret{test{}, err}
}
for h, i := range headers {
if i == -1 {
continue
}
elem := reflect.ValueOf(&e).Elem()
field := elem.FieldByName(h)
if field.CanSet() {
switch field.Type().Name() {
case "float64":
a, _ := strconv.ParseFloat(record[i], 64)
field.Set(reflect.ValueOf(a))
case "Time":
a, _ := time.Parse("2006-01-02T00:00:00Z", record[i])
field.Set(reflect.ValueOf(a))
default:
field.Set(reflect.ValueOf(record[i]))
}
}
}
c <- ret{e, nil}
}
}()
return c
}
package main
import (
"bytes"
"reflect"
"testing"
)
var (
testCSV = `
myid,a,b,prenom,g,s,nom
1,a,b,olivier,g,s,wulveryck
2,a,b,zxcvbn,g,s,wulveryck
3,a,b,qwerty,g,s,wulveryck
`
testObjs = []test{
test{
ID: "1",
Name: "olivier",
Last: "wulveryck",
},
test{
ID: "2",
Name: "zxcvbn",
Last: "wulveryck",
},
test{
ID: "3",
Name: "qwerty",
Last: "wulveryck",
},
}
)
func TestParse(t *testing.T) {
r := bytes.NewReader([]byte(testCSV))
c := parse(r)
var res []test
for v := range c {
res = append(res, v.V)
}
if !reflect.DeepEqual(res, testObjs) {
t.Fail()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment