Manipulate CSV headers while parsing files
I have faced many CSV files representing the same data, or having to be unmarshalled to the same structures, but always with a twist on the headers.
Sometimes, the headers didn't have the proper case. Sometimes, they were just plain wrong. Sometimes, whoever generated the file forgot to trim them.
Unfortunately, Go's csv:"..."
tag is very strict. Take the following example,
a CSV file provided by a French company:
Nom,Numéro
John,0123456789
Anna,0987654321
Unmarshalling this to the following struct in Go is tedious:
type Person struct {
Name string `csv:"NAME"`
PhoneNumber string `csv:"PHONE NUMBER"`
}
It's tedious because the csv:"Phone"
tag doesn´t match the header
Numéro
.
The goal of this library is to make processing of CSV files with "variable" headers simpler.
In order to use this library, one needs to have a csv.Reader
already.
The next requirement is to have a list of the header mappings, as a map.
These go from the file to the struct
.
In our example above, the header replacemenent would be:
headerReplacements := map[string]string{
"Nom": "NAME",
"Numéro": "PHONE NUMBER",
}
Finally, we can build a replacer with:
replacer := csvheaders.NewReplacer(csvReader, headerReplacements)
This replacer
can be fed to csv parsing libraries such as gocsv
or goflat
:
file, err := os.Open("phone_directory.csv")
if err != nil {
...
}
defer file.Close()
csvReader := csvheaders.NewReplacer(
csv.NewReader(file),
map[string]string{
"Nom": "NAME",
"Numéro": "PHONE NUMBER",
})
var rows []*Person
err := gocsv.UnmarshalCSV(csvReader, &rows)
if err != nil {
...
}