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
Related
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.
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
Why is this not dumping out the string? Anyone have any ideas how to get this code working?
package main
import (
"bytes"
"encoding/json"
"fmt"
)
type Tick struct {
Query string `json:"query"`
}
func main() {
data := &Tick{Query: "https://ratesjson.fxcm.com/DataDisplayer?&callback=Tick"}
buf := new(bytes.Buffer)
enc := json.NewEncoder(buf)
enc.SetEscapeHTML(true)
_ = enc.Encode(data)
fmt.Println(string(buf.Tick()))
fmt.Println("Done")
}
Anyone know why this is invalid json or why this can not be parsed? Or point out the fix how to make this work?
package main
import (
"log"
"fmt"
"net/http"
"bytes"
"io/ioutil"
"github.com/pquerna/ffjson/ffjson"
)
type MsgRatesArray struct {
RateQuote []MsgRateQuoteJson `json:"Rates"`
}
type MsgRateQuoteJson struct {
SymbolName string `json:"Symbol"`
SymbolBid int64 `json:"Bid"`
SymbolAsk int64 `json:"Ask"`
SymbolSpread int64 `json:"Spread"`
SymbolPT string `json:"ProductType"`
}
var respBytes []byte
func main() {
var msg MsgRatesArray
response,err := http.Get("https://ratesjson.fxcm.com/DataDisplayer?&callback=Tick")
if err != nil {
log.Fatal(err)
}
defer response.Body.Close()
respBytes, err := ioutil.ReadAll(response.Body)
jsonBytes := respBytes[bytes.Index(respBytes, []byte("{")):bytes.LastIndex(respBytes, []byte("}"))+1]
jsonString := string(jsonBytes)
fmt.Println(jsonString)
err = ffjson.Unmarshal(jsonBytes, &msg)
if err != nil {
panic(err)
}
}
Do your own http request to get the json, then strip out the non json stuff (everything before the first { and after the last }:
response,err := http.Get("https://ratesjson.fxcm.com/DataDisplayer?&callback=Tick")
if err != nil {
log.Fatal(err)
}
defer response.Body.Close()
respBytes, err := ioutil.ReadAll(response.Body)
jsonBytes := respBytes[bytes.Index(respBytes, []byte("{")):bytes.LastIndex(respBytes, []byte("}"))+1]
jsonString := string(jsonBytes)
fmt.Println(jsonString)
https://play.golang.org/p/JyibZ3g6UA
I am fairly new to Go. I have the following code:
package main
import (
"encoding/json"
"fmt"
)
func main() {
byt := []byte(`{"num":6.13,"strs":["a","b"]}`)
dat := []byte(`{"num":7.13,"strs":["c","d"]}`)
if err := json.Unmarshal(byt, &dat); err != nil {
panic(err)
}
fmt.Println(dat)
}
Getting the error:
cannot "unmarshal object into Go value of type []uint8".
How can I fix this please?
You have 2 JSON inputs, and you're trying to unmarshal one into the other. That doesn't make any sense.
Model your JSON input (the object) with a type (struct), and unmarshal into that. For example:
type Obj struct {
Num float64 `json:"num"`
Strs []string `json:"strs"`
}
func main() {
byt := []byte(`{"num":6.13,"strs":["a","b"]}`)
var obj Obj
if err := json.Unmarshal(byt, &obj); err != nil {
panic(err)
}
fmt.Println(obj)
}
Output (try it on the Go Playground):
{6.13 [a b]}
I think you meant to do something like this:
package main
import (
"encoding/json"
"fmt"
)
func main() {
var dat interface{}
byt := []byte(`{"num":6.13,"strs":["a","b"]}`)
if err := json.Unmarshal(byt, &dat); err != nil {
panic(err)
}
fmt.Println(dat)
}
What you were trying to do makes no sense, since you're trying to unmarshal two JSON objects one into another.
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)