使用Interfaces动态映射YAML的更简单方法?

时间:2014-12-01 11:12:38

标签: map go yaml

我正在尝试动态解析yaml文件(因此没有结构)。

package main

import (
    "fmt"
    "gopkg.in/yaml.v2"
    "log"
)

func main() {   
    var out = `
a: First!
f: Second
b:
  c: 
    f: Third
`
    m := make(map[interface{}]interface{})
    err := yaml.Unmarshal([]byte(out), &m)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(m["b"].(map[interface{}]interface{})["c"].(map[interface{}]interface{})["f"])
}

每次我必须访问一个子项时,我都被迫将有问题的map变量转换为(map [interface {}] interface {})。这对我来说有点麻烦,因为我必须遍历地图。

在Go中解析YAML文件有没有更简单的方法?

1 个答案:

答案 0 :(得分:1)

另一种方法是将yaml数据结构展平为键值映射,其中键和值是字符串。然后,如果您需要实际类型(5为int),您可以自己进行转换。例如:

"a" = "First!"
"f" = "Second"
"b.c.f" = "Third"
"b.c.g.size" = "2"
"b.c.g.0 = "zero"
"b.c.g.1 = "one" 

Go:

func main() {
    any := map[string]interface{}{}
    err := yaml.Unmarshal([]byte(out), &any)
    if err != nil {
        log.Fatal(err)
    }

    flatmap := map[string]string{}
    for k, v := range any {
        flatten(k, v, flatmap)
    }

    for k, v := range flatmap {
        fmt.Println(k, "=", v)
    }
}

func flatten(prefix string, value interface{}, flatmap map[string]string) {
    submap, ok := value.(map[interface{}]interface{})
    if ok {
        for k, v := range submap {
            flatten(prefix+"."+k.(string), v, flatmap)
        }
        return
    }
    stringlist, ok := value.([]interface{})
    if ok {
        flatten(fmt.Sprintf("%s.size", prefix), len(stringlist), flatmap)
        for i, v := range stringlist {
            flatten(fmt.Sprintf("%s.%d", prefix, i), v, flatmap)
        }
        return
    }
    flatmap[prefix] = fmt.Sprintf("%v", value)
}