Marshall and UnMarshall JSON Content in GoLang - json

I have a sample json file which is structured like this
{
"method":"brute_force",
"bc":"select * from blah;",
"gc":[
"select sum(year) from blah;",
"select count(*) from table;"
]
}
I am trying to write a go program which can read this file and operate of json content.
package main
import (
"fmt"
"encoding/json"
"io/ioutil"
)
type Response2 struct {
method string
bc string
gc []string
}
func main() {
file,_ := ioutil.ReadFile("config.json")
fmt.Printf("%s",string(file))
res := &Response2{}
json.Unmarshal([]byte(string(file)), &res)
fmt.Println(res)
fmt.Println(res.method)
fmt.Println(res.gc)
}
res.method and res.gc dont print anything. I have no idea on whats going wrong.

type Response2 struct {
method string
bc string
gc []string
}
The name of the fields Must be Uppercase otherwise the Json module can't access them (they are private to your module).
You can use the json tag to specify a match between Field and name
type Response2 struct {
Method string `json:"method"`
Bc string `json:"bc"`
Gc []string `json:"gc"`
}

Related

Error with JSON parsing in Golang

I develop this code:
package main
import (
"fmt"
"io/ioutil"
"encoding/json"
)
type Client struct{
host string
key string
secrete string
username string
password string
}
type Config struct{
Client []Client
}
func main(){
content, err := ioutil.ReadFile("conf2.json")
if err!=nil{
fmt.Print("Error:",err)
}
var conf Config
err=json.Unmarshal(content, &conf)
if err!=nil{
fmt.Print("Error:",err)
}
json.Unmarshal(content, &conf)
fmt.Println(conf.Client[0].host)
}
to parse and print the first host detail from my json, that looks like this:
{
"Client" :
[
{"host":"192.168.1.2"},
{"key":"abcdf"},
{"secrete":"9F6w"},
{"username":"user"},
{"password":"password"}
]
}
But I got an empty string. Could someone know the reason?
Three things to fix:
json.Unmarshal requires the struct fields to be capitalized to be exported or they are ignored
You need the json:"<name>" specifier after the fields so the unmarshal knows the struct field to json mapping
Your json was making multiple clients with one field filled in instead of one client with all the fields filled in
See example: https://play.golang.org/p/oY7SppWNDC
Here, it is the solution to my problem:
package main
import (
"fmt"
"io/ioutil"
"encoding/json"
)
type Client struct {
Host string `json:"host"`
Key string `json:"apikey"`
Secret string `json:"secret"`
Username string `json:"username"`
Password string `json:"password"`
}
type Config struct {
Client Client `json:"Client"`
}
func main(){
jsonmsg, err := ioutil.ReadFile("conf2.json")
conf := new(Config)
err = json.Unmarshal([]byte(jsonmsg), &conf)
if err != nil {
fmt.Print("Error:", err)
}
fmt.Printf("%+v\n%+v\n%+v\n%+v\n%+v\n", conf.Client.Host, conf.Client.Key, conf.Client.Secret, conf.Client.Username,conf.Client.Password)
}

golang convert array of interfaces to strings

I read JSON data from a remote source and convert it to a map. There's some array in the data of which I want to examine the string values. After converting I think m["t"] is an array of interfaces. fmt.Print converts this to printed text on the console but I cannot figure a way to do a simple string comparison like
if val[0] == "str-c" {fmt.Println("success")}
How do I iterate through that and do string comparisons?
package main
import (
"fmt"
"encoding/json"
)
func main() {
var m map[string]interface{}
sJSON := `{"k": "v", "t":["str-a","str-b","str-c"]}`
_ = json.Unmarshal([]byte(sJSON),&m)
// find out if one of the string values of "t" is "str-b"
fmt.Println(m["t"])
}
m["t"] is of type interface{} and is the full array, if you wanted to get str-b it is at index one and you have to do some type assertion to get it as a string. Here's an example; https://play.golang.org/p/W7ZnMgicc7
If you want to check for it in the collection that would look like this;
package main
import (
"fmt"
"encoding/json"
)
func main() {
var m map[string]interface{}
sJSON := `{"k": "v", "t":["str-a","str-b","str-c"]}`
_ = json.Unmarshal([]byte(sJSON),&m)
// find out if one of the string values of "t" is "str-b"
for _, v := range m["t"].([]interface{}) {
if v.(string) == "str-b" {
fmt.Println("match found!")
}
}
//fmt.Println(m["t"].([]interface{})[1].(string))
}
https://play.golang.org/p/vo_90bKw92
If you want to avoid this 'unboxing' stuff, which I would recommend you do, you could instead define a struct to unmarshal into, itwould look like this;
type MyStruct struct {
K string `json:"k"`
T []string `json:"t"`
}
Then you can just range over T without any type assertions and do the compare, working example here; https://play.golang.org/p/ehPxOygGf5

How to parse JSON into data structure

I am trying to parse a JSON of the type
"{\"ids\":[\"a\",\"b\"]}"
Here is my code:
package main
import "fmt"
import "encoding/json"
import "strings"
type Idlist struct {
id []string `json:"ids"`
}
func main() {
var val []byte = []byte(`"{\"ids\":[\"a\",\"b\"]}"`)
jsonBody, _ := strconv.Unquote(string(val))
var holder Idlist
if err := json.NewDecoder(strings.NewReader(jsonBody)).Decode(&holder); err!= nil{
fmt.Print(err)
}
fmt.Print(holder)
fmt.Print(holder.id)
}
However, I keep getting output
{[]}[]
I cannot get the data in the structure.
Where am I going wrong? Here is the playground link: https://play.golang.org/p/82BaUlfrua
Your struct has to look like :
type Idlist struct {
Id []string `json:"ids"`
}
Golang assumes that the fields starting with capital case are public. Hence, your fields are not visible to json decoder. For more details please look into this post :
Why Golang cannot generate json from struct with front lowercase character?
This is example how you can resolve your problem: http://play.golang.org/p/id4f4r9tEr
You might need to use strconv.Unquote on your string.
And this is probably duplicate: How to unmarshal an escaped JSON string in Go?
Resolved: https://play.golang.org/p/hAShmfDUA_
type Idlist struct {
Id []string `json:"ids"`
}

How to unmarshal json in golang when left part is a number

I'd like to unmarshal a json like this in the code. But this code doesn't work. Any suggestions? Thx!
PS. playground here http://play.golang.org/p/m2f94LY_d_
package main
import "encoding/json"
import "fmt"
type Response struct {
Page int
One string "1"
}
func main() {
in := []byte(`{"page":1, "1":"this is 1"}`)
res := &Response{}
json.Unmarshal(in, &res)
fmt.Println(res)
}
You need to tell the json library what the json field names are:
type Response struct {
Page int `json:"page"`
One string `json:"1"`
}
Live: http://play.golang.org/p/CNcvQMqBGD

JSON unmarshaling with long numbers gives floating point number

I was marshaling and unmarshaling JSONs using golang and when I want to do it with number fields golang transforms it in floating point numbers instead of use long numbers, for example.
I have the following JSON:
{
"id": 12423434,
"Name": "Fernando"
}
After marshal it to a map and unmarshal again to a json string I get:
{
"id":1.2423434e+07,
"Name":"Fernando"
}
As you can see the "id" field is in floating point notation.
The code that I am using is the following:
package main
import (
"encoding/json"
"fmt"
"os"
)
func main() {
//Create the Json string
var b = []byte(`
{
"id": 12423434,
"Name": "Fernando"
}
`)
//Marshal the json to a map
var f interface{}
json.Unmarshal(b, &f)
m := f.(map[string]interface{})
//print the map
fmt.Println(m)
//unmarshal the map to json
result,_:= json.Marshal(m)
//print the json
os.Stdout.Write(result)
}
It prints:
map[id:1.2423434e+07 Name:Fernando]
{"Name":"Fernando","id":1.2423434e+07}
It appears to be that the first marshal to the map generates the FP. How can I fix it to a long?
This is the link to the program in the goland playground:
http://play.golang.org/p/RRJ6uU4Uw-
There are times when you cannot define a struct in advance but still require numbers to pass through the marshal-unmarshal process unchanged.
In that case you can use the UseNumber method on json.Decoder, which causes all numbers to unmarshal as json.Number (which is just the original string representation of the number). This can also useful for storing very big integers in JSON.
For example:
package main
import (
"strings"
"encoding/json"
"fmt"
"log"
)
var data = `{
"id": 12423434,
"Name": "Fernando"
}`
func main() {
d := json.NewDecoder(strings.NewReader(data))
d.UseNumber()
var x interface{}
if err := d.Decode(&x); err != nil {
log.Fatal(err)
}
fmt.Printf("decoded to %#v\n", x)
result, err := json.Marshal(x)
if err != nil {
log.Fatal(err)
}
fmt.Printf("encoded to %s\n", result)
}
Result:
decoded to map[string]interface {}{"id":"12423434", "Name":"Fernando"}
encoded to {"Name":"Fernando","id":12423434}
The JSON standard doesn't have longs or floats, it only has numbers. The json package will assume float64 when you haven't defined anything else (meaning, only provided Unmarshal with an interface{}).
What you should do is to create a proper struct (as Volker mentioned):
package main
import (
"encoding/json"
"fmt"
"os"
)
type Person struct {
Id int64 `json:"id"`
Name string `json:"name"`
}
func main() {
//Create the Json string
var b = []byte(`{"id": 12423434, "Name": "Fernando"}`)
//Marshal the json to a proper struct
var f Person
json.Unmarshal(b, &f)
//print the person
fmt.Println(f)
//unmarshal the struct to json
result, _ := json.Marshal(f)
//print the json
os.Stdout.Write(result)
}
Result:
{12423434 Fernando}
{"id":12423434,"name":"Fernando"}
Playground: http://play.golang.org/p/2R76DYVgMK
Edit:
In case you have a dynamic json structure and wish to use the benefits of a struct, you can solve it using json.RawMessage. A variable of type json.RawMessage will store the raw JSON string so that you later on, when you know what kind of object it contains, can unmarshal it into the proper struct. No matter what solution you use, you will in any case need some if or switch statement where you determine what type of structure it is.
It is also useful when parts of the JSON data will only be copied to the another JSON object such as with the id-value of a JSON RPC request.
Example of container struct using json.RawMessage and the corresponding JSON data:
type Container struct {
Type string `json:"type"`
Data json.RawMessage `json:"data"`
}
var b = []byte(`{"type": "person", "data":{"id": 12423434, "Name": "Fernando"}}`)
A modified version of your example on Playground: http://play.golang.org/p/85s130Sthu
Edit2:
If the structure of your JSON value is based on the name of a name/value pair, you can do the same with a:
type Container map[string]json.RawMessage