Unmarshal GO YAML to either a Map or a String

时间:2018-02-01 18:17:27

标签: go yaml

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

3 个答案:

答案 0 :(得分:2)

之前已经以各种方式回答了这个问题,但是很长一段时间以来很容易将其拆分成界面然后处理这两种情况

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)
        }

}

答案 1 :(得分:0)

这只是出色的@Benjamin Kadish answer above的后续版本,但这是一个更完整的版本,它使用yaml.v3,这使其更加明显。请注意,在Yaml v3中,未编组项目的类型为map[string]interface{},而不是map[interface{}]interface{}


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)
        }
    }
}


答案 2 :(得分:-1)

因为,go是静态类型语言,如果将val3转换为已定义的结构,则不能只保留val3: ""列表项。它应该是关键值对。例如。 (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) } )(如果你想要它是空的。)

这是修改后的代码

2018/02/02 01:07:36 {Entry:[map[keya1:val1 keya2:val2] map[keyb2:val2 keyb1:val1] map[val3:]]}

输出:

{{1}}