我正在尝试访问Yaml文件并获取单个值,但我正在努力使用Struct语法来实现此目的。下面的代码处理Yaml,我可以打印完整的Struct,但是如何访问单个ecs.services.name
属性?
关于如何处理这个问题的任何建议都是值得欢迎的,因为我遇到了几个Yaml图书馆但是还没有能够让它们完全发挥作用。
test.yaml:
ecs:
services:
- name: my-service
taskDefinition: my-task-def
desiredCount: 1
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)
}
}
输出
$ 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}}
答案 0 :(得分:3)
我有一个类似的要求,在yaml文件中我需要执行嵌套检索。因为我发现没有开箱即用的解决方案我必须自己写。
我有一个yaml文件,内容如下
"a": "Easy!"
"b":
"c": "2"
"d": ["3", "4"]
"e":
"f": {"g":"hi","h":"6"}
我想从此结构访问和打印嵌套值,输出应如下所示
--- 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
我也不想定义一个结构来保存解析后的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
}
答案 1 :(得分:1)
我认为你有一个额外的嵌套水平。可能不需要Config
结构。你能尝试以下定义:
type Ecs struct {
Services []Service
}
type Service struct {
Name string
TaskDefinition string
DesiredCount int
}
然后尝试解组yaml数据。然后,您可以将数据作为ecs.Services
访问。
答案 2 :(得分:0)
You should use struct tags since you name the fields with lower case letters. This applies to different named fields as well.
See the example for how to fix this: https://play.golang.org/p/WMmlQsqYeB the other answer is incorrect.