How do you parse YAML data, in Go, without knowing its structure in advance? All of the examples I've seen assume you want to decode a marshaled map whose keys you already know. What if you don't know the keys? What if it's not a map but a marshaled list, a scalar, or some other common type?
Though I'm principally concerned with YAML, here, it seems like the technique might be generally useful for JSON, etc.. since there's a general pattern for parsing structured data (tagged structs, obviously).
For JSON, unmarshal the data to an interface{}
value. Use type assertions to determine what's in the value.
var v interface{}
err := json.Unmarshal(data, &v)
if err != nil {
// handle error
}
switch v := v.(type) {
case string:
fmt.Println("string:", v)
case float64:
fmt.Println("number:", v)
case []interface{}:
fmt.Println("array:", v)
case map[string]interface{}:
fmt.Println("object:", v)
case nil:
fmt.Println("nil")
}
In the case of JSON, the standard library json.Unmarshal
function will unmarshal arbitrary JSON if you like, if you pass it a pointer to an uninitialized empty interface. (See this example.)
The official docs even say as much:
To unmarshal JSON into an interface value, Unmarshal stores one of these in the interface value:
bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null
Edit: Though not documented, the same is true of the yaml package; I tested on my workstation, and passing in a pointer to an uninitialized empty interface results in the initialization of correct arrays, maps, and primitives.