[json] Decode JSON with unknown structure

I want to get a string that represents a json like this one:

{ "votes": { "option_A": "3" } }

and include a "count" key in it so it ends like this:

{ "votes": { "option_A": "3" }, "count": "1" }

This is why I planned to convert it to json so I could add the count and then make it a string again. The problem is I don't know the structure of that JSON, so I can't use json.Unmarshal(in, &myStruct) because that struct varies. How can I do this?

This question is related to json go

The answer is


The issue I had is that sometimes I will need to get at a value that is deeply nested. Normally you would need to do a type assertion at each level, so I went ahead and just made a method that takes a map[string]interface{} and a string key, and returns the resulting map[string]interface{}.

The issue that cropped up for me was that at some depths you will encounter a Slice instead of Map. So I also added methods to return a Slice from Map, and Map from Slice. I didnt do one for Slice to Slice, but you could easily add that if needed. Here are the methods:

package main
type Slice []interface{}
type Map map[string]interface{}

func (m Map) M(s string) Map {
   return m[s].(map[string]interface{})
}

func (m Map) A(s string) Slice {
   return m[s].([]interface{})
}

func (a Slice) M(n int) Map {
   return a[n].(map[string]interface{})
}

and example code:

package main

import (
   "encoding/json"
   "fmt"
   "log"
   "os"
)

func main() {
   o, e := os.Open("a.json")
   if e != nil {
      log.Fatal(e)
   }
   in_m := Map{}
   json.NewDecoder(o).Decode(&in_m)
   out_m := in_m.
      M("contents").
      M("sectionListRenderer").
      A("contents").
      M(0).
      M("musicShelfRenderer").
      A("contents").
      M(0).
      M("musicResponsiveListItemRenderer").
      M("navigationEndpoint").
      M("browseEndpoint")
   fmt.Println(out_m)
}

package main

import "encoding/json"

func main() {
    in := []byte(`{ "votes": { "option_A": "3" } }`)
    var raw map[string]interface{}
    if err := json.Unmarshal(in, &raw); err != nil {
        panic(err)
    }
    raw["count"] = 1
    out, err := json.Marshal(raw)
    if err != nil {
        panic(err)
    }
    println(string(out))
}

https://play.golang.org/p/o8ZwvgsQmoO