How can I map a nested JSON to a nested Struct like this:
type ChildStruct1 struct {
key3,
key4,string
}
type ChildStruct2 struct {
key4,
key5,string
}
type MainStruct struct {
key1,
key2,string
childStruct1 ChildStruct1
childStruct2 ChildStruct1
}
Input JSON:
{
key1: val1,
key2: val2,
chilDStruct1 : {
key3: val3,
key4: val4,
}
chilDStruct2 : {
key5: val5,
key6: val6,
}
}
How can this be mapped. I have used jsonMapper in Java but not sure how to do it here. I tried this but this is not working:
var data MainStruct
file, err := ioutil.ReadFile("jsonData.json")
if err != nil {
log.Fatal(err)
}
err = json.Unmarshal(file, &data)
if err != nil {
log.Fatal(err)
}
fmt.Println(data.key1)
I tried this also:
u := &MainStruct{}
file, err := ioutil.ReadFile("jsonData.json")
if err != nil {
log.Fatal(err)
}
err = json.Unmarshal([]byte(file), u)
if err != nil {
log.Fatal(err)
}
fmt.Println(u.key1)
But output is always 0
.
You have quite some errors in your example (both in JSON text and source code). Let's fix them.
First your JSON is not valid. Try this instead of yours:
{
"key1": "val1",
"key2": "val2",
"childStruct1" : {
"key3": "val3",
"key4": "val4"
},
"childStruct2" : {
"key5": "val5",
"key6": "val6"
}
}
Second, your Go source defining your struct types has syntax errors.
Third, you have to export struct fields in order so the json
package can set their values. Try this instead of yours:
type ChildStruct1 struct {
Key3 string
Key4 string
}
type ChildStruct2 struct {
Key4 string
Key5 string
}
type MainStruct struct {
Key1 string
Key2 string
ChildStruct1 ChildStruct1
ChildStruct2 ChildStruct2
}
And now on to the code to parse the JSON text. You can read the whole file into memory using ioutil.ReadFile()
, but often it is more efficient to not read the whole file but to "stream" it to a decoder (using the file as the input).
os.Open()
returns a *File
. It is not a []byte
, but it implements io.Reader
. So you can't pass it to json.Unmarshal()
. Instead create a json.Decoder
using json.NewDecoder()
which accepts an io.Reader
, so you can pass the opened file. And don't forget to close the opened file using File.Close()
, best to close it as a deferred statement (if opening it succeeds).
f, err := os.Open("jsonData.json")
if err != nil {
log.Panic(err)
}
defer f.Close()
var data MainStruct
err = json.NewDecoder(f).Decode(&data)
if err != nil {
log.Panic(err)
}
fmt.Println(data.Key1)
fmt.Printf("%+v", data)
(Note that I used log.Panic()
instead of log.Fatal()
as the latter calls os.Exit()
and hence our deferred function would not be called.)
Output:
val1
{Key1:val1 Key2:val2 ChildStruct1:{Key3:val3 Key4:val4} ChildStruct2:{Key4: Key5:val5}}
Here is a modified version that parses the JSON text from a constant defined in the source code, try it on the Go Playground:
var data MainStruct
err := json.Unmarshal([]byte(input), &data)
if err != nil {
log.Fatal(err)
}
fmt.Println(data.Key1)
fmt.Printf("%+v", data)
Keys in the JSON text start with lowercase letters, struct field names in Go start with uppercase letters (needed in order to be exported), but the json
package is "clever" enough to match them. Should you use something different, you could use tags to specify how a struct field can be found in the json, e.g.
type ChildStruct1 struct {
Key3 string `json:"myKey3"`
Key4 string `json:"myKey4"`
}