Reputation: 814
I have an app that receives messages which are JSON. The JSON has various "sections" (example below). Each section has a name, but the structure beyond that is completely different per section.
What I want to do is go through the sections and for each, Unmarshal into the appropriate object. But strangely I've found this difficult, as it seems you can either Unmarshal the entire JSON into an object, or you can get a generic map[string]interface{}. All the example code I've found gets into type switching and manually assigning variables...I was hoping to do the neato Unmarshal directly into an object.
Is there a way to feed Unmarshal a subset of the JSON? I could slice and dice the byte[] myself but that seems ghastly...surely others have experienced something like this?
Here is what I've played with.
package main
import "encoding/json"
type Book struct {
Author string
Title string
Price float64
}
type Movie struct {
Title string
Year float64
Stars float64
Format string
}
var sections map[string]interface{}
func main() {
/*
* "Book" and "Movie" are "sections".
* There are dozens of possible section types,
* and which are present is not known ahead of time
*/
incoming_msg_string := `
{
"Book" : {
"Author" : "Jack Kerouac",
"Title" : "On the Road",
"Price" : 5.99
},
"Movie" : {
"Title" : "Sherlock Holmes vs. the Secret Weapon",
"Year" : 1940,
"Stars" : 2.5,
"Format" : "DVD"
}
}`
/*
* this code gets me a list of sections
*/
var f interface{}
err := json.Unmarshal([]byte(incoming_msg_string), &f)
if err != nil {
panic(err)
}
var list_of_sections []string
for section_type, _ := range f.(map[string]interface{}) {
list_of_sections = append(list_of_sections, section_type)
}
/*
* next I would like to take the JSON in the "book" section
* and unmarshal it into a Book object, then take the JSON
* in the "movie" section and unmarshal it into a Movie object,
* etc.
*
* https://blog.golang.org/json-and-go has an example on
* decoding arbitrary data, but there's only one Unmarshaling.
*
* json.RawMessage has an example in the docs but it assumes
* the objects are the same type (I think). My attempts to use
* it with a two-field struct (section name, and a raw message)
* gave runtime errors. Likewise unmarshaling into a
* []json.RawMessage gave "panic: json: cannot unmarshal object into Go value of type []json.RawMessage"
*
* What I'm looking for is something like:
* json.Unmarshal(some_json["a certain section"],&object)
*
*/
}
Any breadcrumb trail hints much appreciated.
Upvotes: 3
Views: 3858
Reputation: 4363
Do your initial unmarshal to a type Sections map[string]json.RawMessage
variable. You will then have the section type and the raw data associated with it. You can either switch on the section type and unmarshal to the specific section struct or unmarshal to a map[string]interface{} and handle them generically. (Whatever works best for your app.)
Upvotes: 13