golang: Encode/Decode arbitrary JSON
Just a quick post in case I forget how to do this in future. I had a use case for working with reading arbitrary JSON from a file and parsing it using Golang, which meant that the recommended way of using structs wasn't suitable.
json.Marshal
The first thing to do was marshal a custom data structure into being a JSON string using json.Marshal. This was fairly straightforward to do:
go
cacheContent := map[string]interface{}{"foo": "bar","baz": map[string]interface{}{"bee": "boo",},}str, err := json.Marshal(cacheContent)if err != nil {fmt.Println("Error encoding JSON")return}fmt.Println(string(str))# => {"baz":{"bee":"boo"},"foo":"bar"}
json.Unmarshal
json.Unmarshal was the tough one to work out. As it turns out, all you need to do is define a map of string => interface and then unmarshal into this structure. Go will take care of the rest.
go
# Using the "str" variable that we created using json.Marshal earliervar x map[string]interface{}json.Unmarshal([]byte(str), &x)fmt.Println("%v", x)# => %v map[baz:map[bee:boo] foo:bar]# Using some hand crafted JSON. This could come from a file, web service, anythingstr2 := "{"foo":{"baz": [1,2,3]}}"var y map[string]interface{}json.Unmarshal([]byte(str2), &y)fmt.Println("%v", y)# => %v map[foo:map[baz:[1 2 3]]]
Once the data is un-marshalled, you can access it as follows:
go
fmt.Printf("%v", y["foo"].(map[string]interface{})["baz"])# => [1,2,3]
As we're un-marshalling into an interface, we need to inform go what data type each key is before we can perform operations on it. This is what the .(map[string]interface{})
does