Trying to marshal a csv string to a struct - csv

Here is my program :
package main
import (
"fmt"
"log"
"github.com/gocarina/gocsv"
)
// GeoAdresseCsv is a test structcd
type GeoAdresseCsv struct {
ID int `csv:"id"`
IDBan string `csv:"id_ban"`
}
func main() {
var adresseDB []GeoAdresseCsv
stringCsv := `id;id_ban
2908743;28009_0019_00008`
err := gocsv.UnmarshalString(stringCsv, &adresseDB)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", adresseDB)
}
But the ouput that i get is :
[{ID:0 IDBan:}]
How should i do correctly to get my csv string correctly mapped to my struct ?

While the separator in your data is ;, the package by default seems to use ,.
So we need to configure the package to use a different separator. According to the documentation, this is possible with a customizable CSV reader:
gocsv.SetCSVReader(func(in io.Reader) gocsv.CSVReader {
r := csv.NewReader(in)
r.Comma = ';' // This is our separator now
return r
})
This configures all functions in the package.
Your code should look like this to include the change:
package main
import (
"encoding/csv"
"fmt"
"io"
"log"
"github.com/gocarina/gocsv"
)
// GeoAdresseCsv is a test structcd
type GeoAdresseCsv struct {
ID int `csv:"id"`
IDBan string `csv:"id_ban"`
}
func main() {
gocsv.SetCSVReader(func(in io.Reader) gocsv.CSVReader {
r := csv.NewReader(in)
r.Comma = ';' // This is our separator now
return r
})
var adresseDB []GeoAdresseCsv
stringCsv := `id;id_ban
2908743;28009_0019_00008`
err := gocsv.UnmarshalString(stringCsv, &adresseDB)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", adresseDB)
}
Now the output is the expected value:
[{ID:2908743 IDBan:28009_0019_00008}]
You can run it online here.

Related

json.Decode doesn't decode numbers [duplicate]

This question already has an answer here:
json.Unmarshal returning blank structure
(1 answer)
Closed 2 years ago.
I basically copypasted this code from the documentation of the json package. In the provided example, the values of the JSON objects are strings. Here, I tried using integers instead.
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"strings"
)
func main() {
const jsonStream = `{"serverTime":35678}`
type Message struct {
serverTime int
}
dec := json.NewDecoder(strings.NewReader(jsonStream))
for {
var m Message
if err := dec.Decode(&m); err == io.EOF {
break
} else if err != nil {
log.Fatal(err)
}
fmt.Printf("its %v o clock\n", m.serverTime)
}
}
m.ServerTime should now be 35678, however, it's just 0. What am I doing wrong?
as document describes
The json package only accesses the exported fields of struct types (those that begin with an uppercase letter). Therefore only the the exported fields of a struct will be present in the JSON output.
so change serverTime to ServerTime, and add json tags json:"serverTime"
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"strings"
)
func main() {
const jsonStream = `{"serverTime":35678}`
type Message struct {
ServerTime int `json:"serverTime"`
}
dec := json.NewDecoder(strings.NewReader(jsonStream))
for {
var m Message
if err := dec.Decode(&m); err == io.EOF {
break
} else if err != nil {
log.Fatal(err)
}
fmt.Printf("its %v o clock\n", m.ServerTime)
}
}

Unmarshalling to same struct but different json name

I am trying to unmarshal a particular json data, perform some data transformations and then marshal the data and send it. However I want to marshal it with different json variable name.
Can I marshal the data to another json name like have xyz instead of abc
{"abc":1}
to
{"xyz":1}
package main
import (
"fmt"
"encoding/json"
)
type SomeStruct struct {
SomeField int `json:"abc"`
}
func main(){
jsonData := []byte(`{"abc":1}`)
strct := SomeStruct{}
json.Unmarshal([]byte(jsonData), &strct)
fmt.Println(strct)
x, err := json.Marshal(strct)
if err != nil {
fmt.Println("errs", err)
}
finalValue := string(x)
fmt.Println(finalValue)
}
Define two structures, one for your input, one for your output, and convert like this:
package main
import (
"fmt"
"encoding/json"
)
type inStruct struct {
SomeField int `json:"abc"`
}
type outStruct struct {
SomeField int `json:"xyz"`
}
func main(){
jsonData := []byte(`{"abc":1}`)
strct := inStruct{}
if err := json.Unmarshal(jsonData, &strct); err != nil {
log.Fatal(err)
}
// Edit to reflect mkopriva's comment
// outStruct := &outStruct{SomeField: strct.SomeField}
outStruct := outStruct(strct)
x, err := json.Marshal(outStruct)
if err != nil {
log.Fatal(err)
}
finalValue := string(x)
fmt.Println(finalValue)
}
You can potentially implement a custom ToJSON method for the struct, as follows:
package main
import (
"encoding/json"
"fmt"
)
type SomeStruct struct {
SomeField int `json:"abc"`
}
func (s *SomeStruct) ToJSON() string {
return fmt.Sprintf("{\"xyz\":%d}", s.SomeField)
}
func main() {
jsonData := []byte(`{"abc":1}`)
strct := SomeStruct{}
json.Unmarshal([]byte(jsonData), &strct)
fmt.Println(strct)
x, err := json.Marshal(strct)
if err != nil {
fmt.Println("errs", err)
}
finalValue := string(x)
fmt.Println(finalValue)
fmt.Println("custom ToJSON", strct.ToJSON())
}
Playground link: https://play.golang.org/p/mjW0dBPN59Q
It might not be flexible in the long run though. Personally, for requirement like this, I would prefer the solution posted by #Clément

Can get value of JSON in Go

I'm new in Go. I'm trying to read a JSON file and get a part of it for then operate with the values obtained.
My JSON is in the file example.json:
{"results":[{"statement_id":0,"series":[{"name":"cpu/node_utilization","columns":["time","distinct"],"values":[[10,1],[11,3],[13,5]]}]}]}
So what I would like to get is the "values" for get the sum of all the elements. In this case: 1+3+5
Here is the code that I have. I'm available to get the results, but then I don't manage to get series.
Here is the code that I have:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
)
func main() {
// Open our jsonFile
jsonFile, err := os.Open("example.json")
// if we os.Open returns an error then handle it
if err != nil {
fmt.Println(err)
}
fmt.Println("Successfully Opened example.json")
// defer the closing of our jsonFile so that we can parse it later on
defer jsonFile.Close()
byteValue, _ := ioutil.ReadAll(jsonFile)
var all_data map[string]interface{}
json.Unmarshal([]byte(byteValue), &all_data)
fmt.Println(all_data["results"])
}
I've tried diferent solutions like
all_data["results"].(map[string]interface{})["series"])
But the problem is that the map is in an array, and I don't know how to solve it.
Using interfaces and map
package main
import (
"encoding/json"
"fmt"
)
func main() {
byteValue := []byte(`{"results":[{"statement_id":0,"series":[{"name":"cpu/node_utilization","columns":["time","distinct"],"values":[[10,1],[11,3],[13,5]]}]}]}`)
var all_data map[string][]interface{}
json.Unmarshal([]byte(byteValue), &all_data)
fmt.Println("result:", all_data["results"])
for _, r := range all_data["results"] {
s := r.(map[string]interface{})
fmt.Println("series:", s["series"])
w := s["series"].([]interface{})
for _, x := range w {
y := x.(map[string]interface{})
fmt.Println(y)
z := y["values"].([]interface{})
fmt.Println("values:", z)
for _, v := range z {
u := v.([]interface{})
fmt.Println(u)
for _, i := range u {
val := i.(float64)
fmt.Println(val)
}
}
}
}
}
I have solved defining an Struct.
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
)
type AutoGenerated struct {
Results []struct {
StatementID int `json:"statement_id"`
Series []struct {
Name string `json:"name"`
Columns []string `json:"columns"`
Values [][]int `json:"values"`
} `json:"series"`
} `json:"results"`
}
func main() {
// Open our jsonFile
jsonFile, err := os.Open("example.json")
// if we os.Open returns an error then handle it
if err != nil {
fmt.Println(err)
}
fmt.Println("Successfully Opened example.json")
// defer the closing of our jsonFile so that we can parse it later on
defer jsonFile.Close()
byteValue, _ := ioutil.ReadAll(jsonFile)
all_data := AutoGenerated{}
json.Unmarshal([]byte(byteValue), &all_data)
fmt.Println(all_data.Results[0].Series[0].Values)
}
I have used this web to generate automatically the Struct providing the JSON structure

How to use switch in GO with json keys?

Here is an example of POST request body:
{"action":"do_something","id":"001"}
I took an example of simple json parser
package main
import (
"encoding/json"
"fmt"
"net/http"
)
type some_json struct {
Action string `json:"action"`
Id string `json:"id"`
}
func jsonparse(rw http.ResponseWriter, request *http.Request) {
decoder := json.NewDecoder(request.Body)
var post_data some_json
err := decoder.Decode(&post_data)
if err != nil {
panic(err)
}
switch ***WHAT_SHOULD_BE_HERE???*** {
default :
fmt.Fprintf(w,"WRONG PARAM")
case "some_thing":
fmt.Fprintf(w,post_data.Id + "\n\n")
}
}
func main() {
http.HandleFunc("/", jsonparse)
http.ListenAndServe(":8080", nil)
}
I already know how to switch cases from form values, but
how to switch cases of json key values?
I am not sure what you want to switch, but i think that you just need to erase the () so Action is not a function call anymore
Be careful maybe your error is that u mixed up the strings
in JSON: "do_something"
in case: "some_thing"
You can copy following code to playground
package main
import (
"encoding/json"
"fmt"
"strings"
)
type some_json struct {
Action string `json:"action"`
Id string `json:"id"`
}
func jsonparse() {
r := strings.NewReader("{\"action\":\"do_something\",\"id\":\"001\"}")
decoder := json.NewDecoder(r)
var post_data some_json
err := decoder.Decode(&post_data)
if err != nil {
panic(err)
}
switch post_data.Action {
default:
fmt.Println( "WRONG PARAM")
case "do_something":
fmt.Println( post_data.Id+"\n\n")
}
}
func main() {
jsonparse()
}

Write Struct to Json File using Struct Fields (not json keys)

How can I read a json file into a struct, and then Marshal it back out to a json string with the Struct fields as keys (rather than the original json keys)?
(see Desired Output to Json File below...)
Code:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
)
type Rankings struct {
Keyword string `json:"keyword"`
GetCount uint32 `json:"get_count"`
Engine string `json:"engine"`
Locale string `json:"locale"`
Mobile bool `json:"mobile"`
}
func main() {
var jsonBlob = []byte(`
{"keyword":"hipaa compliance form", "get_count":157, "engine":"google", "locale":"en-us", "mobile":false}
`)
rankings := Rankings{}
err := json.Unmarshal(jsonBlob, &rankings)
if err != nil {
// nozzle.printError("opening config file", err.Error())
}
rankingsJson, _ := json.Marshal(rankings)
err = ioutil.WriteFile("output.json", rankingsJson, 0644)
fmt.Printf("%+v", rankings)
}
Output on screen:
{Keyword:hipaa compliance form GetCount:157 Engine:google Locale:en-us Mobile:false}
Output to Json File:
{"keyword":"hipaa compliance form","get_count":157,"engine":"google","locale":"en-us","mobile":false}
Desired Output to Json File:
{"Keyword":"hipaa compliance form","GetCount":157,"Engine":"google","Locale":"en-us","Mobile":false}
If I understand your question correctly, all you want to do is remove the json tags from your struct definition.
So:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
)
type Rankings struct {
Keyword string
GetCount uint32
Engine string
Locale string
Mobile bool
}
func main() {
var jsonBlob = []byte(`
{"keyword":"hipaa compliance form", "get_count":157, "engine":"google", "locale":"en-us", "mobile":false}
`)
rankings := Rankings{}
err := json.Unmarshal(jsonBlob, &rankings)
if err != nil {
// nozzle.printError("opening config file", err.Error())
}
rankingsJson, _ := json.Marshal(rankings)
err = ioutil.WriteFile("output.json", rankingsJson, 0644)
fmt.Printf("%+v", rankings)
}
Results in:
{Keyword:hipaa compliance form GetCount:0 Engine:google Locale:en-us Mobile:false}
And the file output is:
{"Keyword":"hipaa compliance form","GetCount":0,"Engine":"google","Locale":" en-us","Mobile":false}
Running example at http://play.golang.org/p/dC3s37HxvZ
Note: GetCount shows 0, since it was read in as "get_count". If you want to read in JSON that has "get_count" vs. "GetCount", but output "GetCount" then you'll have to do some additional parsing.
See Go- Copy all common fields between structs for additional info about this particular situation.
Try to change the json format in the struct
type Rankings struct {
Keyword string `json:"Keyword"`
GetCount uint32 `json:"Get_count"`
Engine string `json:"Engine"`
Locale string `json:"Locale"`
Mobile bool `json:"Mobile"`
}
An accourance happened by just using json.Marshal() / json.MarshalIndent().
It overwrites the existing file, which in my case was suboptimal. I just wanted to add content to current file, and keep old content.
This writes data through a buffer, with bytes.Buffer type.
This is what I gathered up so far:
package srf
import (
"bytes"
"encoding/json"
"os"
)
func WriteDataToFileAsJSON(data interface{}, filedir string) (int, error) {
//write data as buffer to json encoder
buffer := new(bytes.Buffer)
encoder := json.NewEncoder(buffer)
encoder.SetIndent("", "\t")
err := encoder.Encode(data)
if err != nil {
return 0, err
}
file, err := os.OpenFile(filedir, os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
return 0, err
}
n, err := file.Write(buffer.Bytes())
if err != nil {
return 0, err
}
return n, nil
}
This is the execution of the function, together with the standard json.Marshal() or json.MarshalIndent() which overwrites the file
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
minerals "./minerals"
srf "./srf"
)
func main() {
//array of Test struct
var SomeType [10]minerals.Test
//Create 10 units of some random data to write
for a := 0; a < 10; a++ {
SomeType[a] = minerals.Test{
Name: "Rand",
Id: 123,
A: "desc",
Num: 999,
Link: "somelink",
People: []string{"John Doe", "Aby Daby"},
}
}
//writes aditional data to existing file, or creates a new file
n, err := srf.WriteDataToFileAsJSON(SomeType, "test2.json")
if err != nil {
log.Fatal(err)
}
fmt.Println("srf printed ", n, " bytes to ", "test2.json")
//overrides previous file
b, _ := json.MarshalIndent(SomeType, "", "\t")
ioutil.WriteFile("test.json", b, 0644)
}
Why is this useful?
File.Write() returns bytes written to the file! So this is perfect if you want to manage memory or storage.
WriteDataToFileAsJSON() (numberOfBytesWritten, error)