How do I parse JSON in golang? - json

I tried to "Unmarshal" json in golang, but it doesn't seem to be working.
I get 0 printed out instead of 1. What am I doing wrong?
package main
import (
"fmt"
"encoding/json"
)
type MyTypeA struct {
a int
}
func main() {
var smthng MyTypeA
jsonByteArray := []byte(`{"a": 1}`)
json.Unmarshal(jsonByteArray, &smthng)
fmt.Println(smthng.a)
}

Two problems with your code.
You need to export fields or Marshal won't work, read about it here.
Your package must be called main or func main won't be executed.
http://play.golang.org/p/lJixko1QML
type MyTypeA struct {
A int
}
func main() {
var smthng MyTypeA
jsonByteArray := []byte(`{"a": 1}`)
json.Unmarshal(jsonByteArray, &smthng)
fmt.Println(smthng.A)
}

Related

Parse key containing unicode characters in JSON with Go

I have an API response like this:
{
"Pass ✔": true
}
In Go I use this code:
type Status struct {
Pass bool `json:"Pass ✔"`
}
// ...
var s Status
json.Unmarshal(body, &s)
fmt.Println(s.Pass) // false, where it should be true
How can I correctly unmarshal this JSON document?
As others mentioned, it's not currently possible to do that. As a workaround, you could do something like this:
package main
import (
"encoding/json"
"fmt"
)
type status map[string]bool
func (s status) pass() bool {
return s["Pass ✔"]
}
func main() {
data := []byte(`{"Pass ✔": true}`)
var stat status
json.Unmarshal(data, &stat)
pass := stat.pass()
fmt.Println(pass) // true
}

JSON tag to decode into a struct in Golang

I have a JSON like this:
{
"add":[{"id": "1234ABCD"}, {"id": "5678EFGH"}]
}
And I have a struct like this:
type ExampleStruct struct {
Added []string
}
I am wondering what JSON tag I should put in my struct so that after I do the JSON decoding (code not shown here) and then call exampleStruct := &ExampleStruct followed by exampleStruct.Added, how can I get ["1234ABCD", "5678EFGH"]?
I tried doing this:
type ExampleStruct struct {
Added []string `json:"add"`
}
But it didn't work.
Use a slice of maps instead of strings, as you have key-value pairs of strings.
type ExampleStruct struct {
Added []map[string]string `json:"add"`
}
Here is a full example:
package main
import (
"bytes"
"encoding/json"
"fmt"
)
func main() {
const code = `{
"add":[{"id": "1234ABCD"}]
}`
type ExampleStruct struct {
Added []map[string]string `json:"add"`
}
var data ExampleStruct
json.NewDecoder(bytes.NewReader([]byte(code))).Decode(&data)
fmt.Println(data)
}
EDIT
Since you want to have only the values of the maps, here is a complete example where Added is a function that can be called on the ExampleStruct. It assumes that each map only contains two strings (id and value):
package main
import (
"bytes"
"encoding/json"
"fmt"
)
func main() {
const code = `{
"add":[{"id": "1234ABCD"}, {"id": "5678EFGH"}]
}`
var data ExampleStruct
json.NewDecoder(bytes.NewReader([]byte(code))).Decode(&data)
fmt.Println(data)
fmt.Println(data.Added())
}
type ExampleStruct struct {
Add []map[string]string `json:"add"`
}
func (e ExampleStruct) Added() []string {
values := make([]string, len(e.Add))
for i := range e.Add {
for _, v := range e.Add[i] {
values[i] = v
}
}
return values
}
have you tried to obtain its key by adding 'id', like this
type ExampleStruct struct {
Added []string json:"add.id"
}
You need to arrange your json such a way that elements of the struct should be accessible directly (without over-engineering it).
package main
import (
"bytes"
"encoding/json"
"fmt"
)
type ExampleStruct struct {
Add []struct {
ID string `json:"id"`
} `json:"add"`
}
func main() {
const code = `{
"add":[{"id": "1234ABCD"}, {"id": "5678EFGH"}]
}`
var data ExampleStruct
json.NewDecoder(bytes.NewReader([]byte(code))).Decode(&data)
fmt.Println(data) //Get all ids: {[{1234ABCD} {5678EFGH}]}
fmt.Println(data.Add[0].ID) //Get 1st ID : 1234ABCD
fmt.Println(data.Add[1].ID) //Get 2nd ID ... and so on.: 5678EFGH
}
You can find the code here https://play.golang.org/p/7tD4fLBewp .
If you have many ids in an array then you can also write a function to loop over the array i.e data.Addand get ids from that.

Golang Function Call in Map

I am a newbie at GO Programming. Here is scenario :-
There exists a JSON file that looks like this :-
{
"template": "linuxbase1",
"checkname": ["check_disk"],
"checkmethod": ["check_disk"]
}
I am Unmarshalling this data into a structure :-
package func1
import (
"io/ioutil"
"os"
"encoding/json"
"fmt"
)
type pluginfunc func() string
type Plugindata struct {
Template string `json:"template"`
Checkname []string `json:"checkname"`
Checkmethod []pluginfunc `json:"checkmethod"`
}
var (
Templatepath = "json_sample1.json"
Templateitems Plugindata
)
func Gettemplatedata() {
tdata, err := ioutil.ReadFile(Templatepath)
if err != nil {
fmt.Printf("Unable to read file %s. Error - %v\n",Templatepath, err.Error())
os.Exit(3)
}
json.Unmarshal(tdata, &Templateitems)
}
The "check_disk" function is here :-
package func1
func check_disk() string {
return "Called check_disk"
}
This is the program with main() :-
package main
import (
"fmt"
"checksexpt/func1"
)
func main() {
func1.Gettemplatedata()
fmt.Printf("Templateitems in Main() => %v\n",func1.Templateitems)
for index,funcname := range func1.Templateitems.Checkmethod {
fmt.Printf("%d = %s\n",index,funcname())
}
}
As expected, when I run main(); I see the error :-
Templateitems in Main() => {linuxbase1 [check_cpu check_disk] [<nil> <nil>]}
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0x40115e]
goroutine 1 [running]:
panic(0x50e980, 0xc82000a100)
/opt/go/src/runtime/panic.go:481 +0x3e6
So, I am trying to grab a string from the JSON file and treat it as a function call. That obviously fails ! But, the primary constraint here is that the function names have to be picked from the JSON file. How can I do this ? I know that I can create a static map as follows :-
type checkfunc func() string
var (
Templateitems = map[string]map[string]checkfunc {
"linuxbase1": {
"check_disk": check_disk,
},
}
)
So, A call like - Templateitems["linuxbase1"]["check_disk"]() would work just fine. But, I dont want to create any such static map as the elements in that map needs to keep growing. Any ideas on this?
There is no direct way to parse a function directly from a JSON value. Also, you cannot use string values to refer to variables. So a string check_cpu would not be able to refer to the function with the same name directly.
What you can do instead is parse the json string as is and have a global map for functions. That way, you can call your functions like so:
var funcMap = map[string]pluginfunc{
"check_disk": check_disk,
"check_cpu": check_cpu
}
In your main loop:
for index, funcname := range func1.Templateitems.Checkmethod {
fmt.Printf("%d = %s\n", index, funcMap[funcname]())
}
If however, you really need to put the value in your structure, you can try implementing UnmarshalJSON from the json.Unmarshaler interface. A simple example would be:
type pf map[string]pluginfunc
type Plugindata struct {
Template string `json:"template"`
Checkname []string `json:"checkname"`
Checkmethod pf `json:"checkmethod"`
}
func (p *pf) UnmarshalJSON(data []byte) error {
d := []string{}
if err := json.Unmarshal(data, &d); err != nil {
return err
}
*p = make(pf)
for _, s := range d {
(*p)[s] = funcMap[s]
}
return nil
}
var funcMap = pf{
"check_disk": check_disk,
"check_cpu": check_cpu
}
func main() {
json.Unmarshal(tdata, &Templateitems)
for k, f := range Templateitems.Checkmethod {
fmt.Printf("%s -- %s\n", k, f())
}
}
Working code
Note that this way is not as readable or simple as the first method and it still relies on a function map.
You can read more about json.Unmarshaler here.

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

Go: Convert Strings Array to Json Array String

Trying to convert a strings array to a json string in Go. But all I get is an array of numbers.
What am I missing?
package main
import (
"fmt"
"encoding/json"
)
func main() {
var urls = []string{
"http://google.com",
"http://facebook.com",
"http://youtube.com",
"http://yahoo.com",
"http://twitter.com",
"http://live.com",
}
urlsJson, _ := json.Marshal(urls)
fmt.Println(urlsJson)
}
Code on Go Playground: http://play.golang.org/p/z-OUhvK7Kk
By marshaling the object, you are getting the encoding (bytes) that represents the JSON string. If you want the string, you have to convert those bytes to a string.
fmt.Println(string(urlsJson))
Another way is to use directly os.Stdout.Write(urlsJson)
You could use stdout output encoder:
package main
import (
"encoding/json"
"os"
)
func main() {
json.NewEncoder(os.Stdout).Encode(urls)
}
or a string builder:
package main
import (
"encoding/json"
"strings"
)
func main() {
b := new(strings.Builder)
json.NewEncoder(b).Encode(urls)
print(b.String())
}
https://golang.org/pkg/encoding/json#NewEncoder