在Go中解析不熟悉的YAML / JSON文件

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.