【问题标题】:How to parse a specific key from a map interface?如何从地图界面解析特定键?
【发布时间】:2019-04-11 15:11:13
【问题描述】:

我正在读取一个 yaml 文件,并将其解组为 map[interface{}]interface{}。目标是替换 yaml 中的某个值,并使用替换的值更新读入的文件。我不确定如何解析地图以获取我想要更改的特定键 (password)。我相信你可以使用reflect,但我不能 100% 确定语法

我正在阅读的 YAML 文件 (config.yml):

i_name: example

instances:
  - name: test-instance
    command: get
    arguments:
        hostname: localhost
        port: 203
        username: test
        password: testing123
    labels:
        env: dev

到目前为止的代码:

func replaceConfigPassword() {
    yamlFile, err := ioutil.ReadFile("config.yml")
    fatalIfErr(err)

    m := make(map[interface{}]interface{})

    err = yaml.Unmarshal(yamlFile, &m)
    fatalIfErr(err)

    fmt.Println(m)

    val := reflect.ValueOf(m["instances"]["arguments"]["password"])
    fmt.Println("val=", val)

【问题讨论】:

  • 你不需要反思,只需要type assertion。你也不需要map[interface{}]interface{},只需要map[string]interface{}
  • 你试过用github.com/spf13/viper吗?
  • @MaddEye - 我尝试了 viper,但我只使用以下代码获得输出 map[]m := make(map[string]interface{})err = viper.Unmarshal(&m)fatalIfErr(err)fmt.Println(m)val := viper.GetStringMap("instances.arguments.password")fmt.Println(val)
  • 我希望你意识到,如果你的 YAML 比你的小子集限制更少,并且包含标签、cmets、非十进制整数、引用/文字/折叠标量,这至少会被删除,它YAML 完全加载。

标签: go yaml


【解决方案1】:

以下显示了您如何通过 yaml 单步获取密码:

package main

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

func main() {
    in := []byte(`
i_name: example

instances:
  - name: test-instance
    command: get
    arguments:
        hostname: localhost
        port: 203
        username: test
        password: testing123
    labels:
        env: dev
`)

    m := make(map[string]interface{})
    if err := yaml.Unmarshal(in, &m); err != nil {
        panic(err)
    }
    fmt.Printf("%+v\n", m)

    instances := m["instances"].([]interface{})
    fmt.Printf("%+v\n", instances)

    first := instances[0]
    fmt.Printf("%+v\n", first)

    arguments := first.(map[interface{}]interface{})["arguments"]
    fmt.Printf("%+v\n", arguments)

    password := arguments.(map[interface{}]interface{})["password"]
    fmt.Printf("%+v\n", password)
}
$ go run main.go
map[i_name:example instances:[map[name:test-instance command:get arguments:map[password:testing123 hostname:localhost port:203 username:test] labels:map[env:dev]]]]
[map[name:test-instance command:get arguments:map[hostname:localhost port:203 username:test password:testing123] labels:map[env:dev]]]
map[name:test-instance command:get arguments:map[hostname:localhost port:203 username:test password:testing123] labels:map[env:dev]]
map[username:test password:testing123 hostname:localhost port:203]
testing123

如果您事先知道输入结构,另一种选择可能是对其进行显式建模:

type Config struct {
    IName string `yaml:"i_name"`
    Instances []struct{
        Name string
        Command string
        Arguments map[string]interface{}
        Labels map[string]string
    }
}

    var c Config
    if err := yaml.Unmarshal(in, &c); err != nil {
        panic(err)
    }
    fmt.Printf("%+v\n", c)
    fmt.Printf("%+v\n", c.Instances[0].Arguments["password"])
$ go run main.go

{IName:example Instances:[{Name:test-instance Command:get Arguments:map[hostname:localhost port:203 username:test password:testing123] Labels:map[env:dev]}]}
testing123

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-02
    • 1970-01-01
    • 2016-01-29
    • 2020-05-15
    • 1970-01-01
    • 2021-10-31
    • 2015-11-18
    • 1970-01-01
    相关资源
    最近更新 更多