我正在尝试访问 Yaml 文件并获取单个值,但我正在努力使用 Struct 语法来实现这一点。下面的代码处理 Yaml,我可以打印完整的 Struct,但如何访问单个ecs.services.name属性?
欢迎任何有关如何处理此问题的建议,因为我遇到了几个 Yaml 库,但无法让它们中的任何一个完全工作。
测试.yaml:
ecs:
services:
- name: my-service
taskDefinition: my-task-def
desiredCount: 1
Run Code Online (Sandbox Code Playgroud)
yaml.go
package main
import (
"fmt"
"io/ioutil"
"path/filepath"
"gopkg.in/yaml.v2"
)
type Config struct {
//Ecs []map[string]string this works for ecs with name
Ecs struct {
Services []struct {
Name string
TaskDefinition string
DesiredCount int
}
}
//Services []map[string][]string
}
func main() {
filename, _ := filepath.Abs("test.yaml")
yamlFile, err := ioutil.ReadFile(filename)
check(err)
var config Config
err = yaml.Unmarshal(yamlFile, &config)
check(err)
fmt.Printf("Description: %#v\n", config.Ecs.Services)
}
func check(e error) {
if e != nil {
panic(e)
}
}
Run Code Online (Sandbox Code Playgroud)
输出
$ go run yaml.go
Description: []struct { Name string; TaskDefinition string; DesiredCount int }{struct { Name string; TaskDefinition string; DesiredCount int }{Name:"my-service", TaskDefinition:"", DesiredCount:0}}
Run Code Online (Sandbox Code Playgroud)
小智 5
我有一个类似的要求,需要在 yaml 文件上执行嵌套检索。由于我发现没有开箱即用的解决方案,我不得不自己编写。
我有一个 yaml 文件,其内容如下
"a": "Easy!"
"b":
"c": "2"
"d": ["3", "4"]
"e":
"f": {"g":"hi","h":"6"}
Run Code Online (Sandbox Code Playgroud)
我想访问并打印此结构中的嵌套值,输出应如下所示
--- yaml->a: Easy!
--- yaml->b->c: 2
--- yaml->b->x: None //not existing in the yaml
--- yaml->y->w: None //not existing in the yaml
--- yaml->b->d[0]: 3 //accessing value from a list
--- yaml->e->f->g: hi
Run Code Online (Sandbox Code Playgroud)
我也不想定义一个结构来保存解析的 yaml。golang中最通用的结构是interface{}。解组 yaml 的最合适的结构是map[interface{}]interface{}. 对于来自 java 的人来说,这类似于Map<Object,Object>. 一旦数据被解组,我就必须编写一个函数,它可以使用嵌套键遍历结构并返回值。
下面是执行此操作的代码。打开注释并执行就可以知道代码是如何遍历嵌套结构并最终获取值的。尽管此示例假设 yaml 中的所有值都是字符串,但这也可以扩展为数字键和值。
package main
import (
"fmt"
"gopkg.in/yaml.v2"
"io/ioutil"
"reflect"
)
func main() {
testFile := "test.yaml"
testYaml, rerr := ioutil.ReadFile(testFile)
if rerr != nil {
fmt.Errorf("error reading yaml file: %v", rerr)
}
m := make(map[interface{}]interface{})
if uerr := yaml.Unmarshal([]byte(testYaml), &m); uerr != nil {
fmt.Errorf("error parsing yaml file: %v", uerr)
}
fmt.Printf("--- yaml->a: %v\n\n", getValue(m, []string{"a"}, -1)) //single value in a map
fmt.Printf("--- yaml->b->c: %v\n\n", getValue(m, []string{"b", "c"}, -1)) //single value in a nested map
fmt.Printf("--- yaml->b->x: %v\n\n", getValue(m, []string{"b", "x"}, -1)) //value for a non existent nest key
fmt.Printf("--- yaml->y->w: %v\n\n", getValue(m, []string{"y", "w"}, -1)) //value for a non existent nest key
fmt.Printf("--- yaml->b->d[0]: %v\n\n", getValue(m, []string{"b", "d"}, 0))
fmt.Printf("--- yaml->e->f->g: %v\n\n", getValue(m, []string{"e", "f", "g"}, -1))
}
func getValue(obj map[interface{}]interface{}, keys []string, indexOfElementInArray int) string {
//fmt.Printf("--- Root object:\n%v\n\n", obj)
value := "None"
queryObj := obj
for i := range keys {
if queryObj == nil {
break
}
if i == len(keys)-1 {
break
}
key := keys[i]
//fmt.Printf("--- querying for sub object keyed by %v\n", key)
if queryObj[key] != nil {
queryObj = queryObj[key].(map[interface{}]interface{})
//fmt.Printf("--- Sub object keyed by %v :\n%v\n\n", key, queryObj)
} else {
//fmt.Printf("--- No sub object keyed by %v :\n%v\n\n", key)
break
}
}
if queryObj != nil {
lastKey := keys[len(keys)-1]
//fmt.Printf("--- querying for value keyed by %v\n", lastKey)
if queryObj[lastKey] != nil {
objType := reflect.TypeOf(queryObj[lastKey])
//fmt.Printf("Type of value %v\n", objType)
if objType.String() == "[]interface {}" {
//fmt.Printf("Object is a array %v\n", objType)
tempArr := queryObj[lastKey].([]interface{})
//fmt.Printf("Length of array is %v\n", len(tempArr))
if indexOfElementInArray >= 0 && indexOfElementInArray < len(tempArr) {
value = queryObj[lastKey].([]interface{})[indexOfElementInArray].(string)
}
} else {
value = queryObj[lastKey].(string)
}
}
}
return value
}
Run Code Online (Sandbox Code Playgroud)
我认为你有一个额外的嵌套级别。该Config结构可能不是必需的。您可以尝试以下定义:
type Ecs struct {
Services []Service
}
type Service struct {
Name string
TaskDefinition string
DesiredCount int
}
Run Code Online (Sandbox Code Playgroud)
然后尝试解组 yaml 数据。然后您也许可以以ecs.Services.