Unmarshal GO YAML to either a Map or a String
Solution 1
This has been answered in various ways before, but long story short it is easy unmarshall into an interface and then deal with both cases
type Entry interface{}
for _, entry := range out.Entry {
switch i := entry.(type) {
case string:
log.Printf("i is a string %+v\n", i)
case map[interface{}]interface{}:
log.Printf("i is a map %+v\n", i)
}
}
Solution 2
This is just a followup to the excellent @Benjamin Kadish answer above, but here's a somewhat more complete version and this uses yaml.v3, which makes it just a bit more obvious. Note that the type of the unmarshalled items is map[string]interface{}
instead of map[interface{}]interface{}
in yaml v3.
package main
import (
"gopkg.in/yaml.v3"
"log"
)
type Data struct {
Entry []Entry `yaml:"entries"`
}
type Entry interface {}
var dat string = `
entries:
- keya1: val1
keya2: val2
- keyb1: val1
keyb2: val2
- val3`
func main() {
out := Data{}
if err := yaml.Unmarshal([]byte(dat), &out); err != nil {
log.Fatal(err)
}
for _, entry := range out.Entry {
switch i := entry.(type) {
case string:
log.Printf("i is a string: %+v\n", i)
case map[string]interface{}:
log.Printf("i is a map.")
for k,v := range i {
log.Printf("%s=%v\n",k,v)
}
default:
log.Printf("Type i=%s", i)
}
}
}
Naatan
Updated on June 09, 2022Comments
-
Naatan about 2 years
I'm trying to unmarshal YAML entries that can be either a string or a list of key: value strings (a map as per Go). I cannot figure out how to get this done sadly. I know I can write my own unmarshaller but that seems to only work with structs.
I have the first part working:
package main import ( "log" "gopkg.in/yaml.v2" ) type Data struct { Entry []Entry `yaml:"entries"` } type Entry map[string]string var dat string = ` entries: - keya1: val1 keya2: val2 - keyb1: val1 keyb2: val2 - val3` func main() { out := Data{} if err := yaml.Unmarshal([]byte(dat), &out); err != nil { log.Fatal(err) } log.Printf("%+v", out) }
But the
- val3
entry causes an error now, obviously. How can I get it to recognise both lists and single string entries?Thank you
-
Naatan over 6 yearsThis just isn't true, it just means the code parsing the yaml needs to be typed properly. The input format should not affect this beyond making it a bit more challenging to parse.
-
Naatan over 6 yearsMuch simpler than what I was thinking (I was writing an unmarshaller). Thank you!
-
Abu Hanifa over 6 yearsYes, I thought, you want to convert to your struct. So, if struct is okay, then needs to change yaml :)