yaml库
import "gopkg.in/yaml.v2"
该库可以很方便的操作yaml文件,这里先展示一下常用的解析方法:
假设有如下a.yml
文件:
a: 10
b:
- 1
- 2
- 3
这个yaml很简单,里面包含了一个int
型的变量a
,和一个int
型的数组变量b
。那么与之对应的结构体也很好构造:
type YmlObj struct {
A int
B []int
}
使用yaml包来解析也很简单,这里我就用go的单元测试来写这个方法了:
func TestGetYamlByUnmarshal(t *testing.T) {
y := YmlObj{}
content, err := ioutil.ReadFile("a.yml")
if err != nil{
t.Error(err)
}
if err = yaml.Unmarshal(content, &y);err != nil{
t.Error(err)
}
fmt.Println(y)
}
/*
OUTPUT:
{10 [1 2 3]}
*/
多文档
这里说的多文档,并不是指多个yaml文件,这很简单和上面没什么区别。
在yaml中,严格的讲,每个yaml文件都应该以---
开头,注意,这是三个短横线。因此如果在一个yaml文件中包含多个---
,那么就相当于多个yml文档,例如b.yml:
---
a: 10
b:
- 1
- 2
- 3
---
a: 20
b:
- 4
- 5
这种情况在k8s中非常常见,我之前自己处理的时候想法也很简单,将文件读取为字符串,然后用strings.split(str, "---")
来把这个文件分割为多个文档,然后在逐一解析。
可是这样是有问题的,前几天我遇到一份yml文档中包含多个连续的短横线,那结果也可以预见:yml文档被分割成了多个不完整的部分,解析自然也会失败。
实际上yaml这个包对于这种情况是有官方的解决方案的:decode
下面上代码:
func TestGetYaml(t *testing.T) {
file, err := os.Open("b.yaml")
if err != nil{
t.Error(err)
}
dec := yaml.NewDecoder(file)
y := YmlObj{}
err := dec.Decode(&y)
for err == nil{
fmt.Println(y)
err = dec.Decode(&y)
}
if !errors.Is(err, io.EOF){
t.Error(err)
}
fmt.Println("Parse yaml complete!")
}
/*
OUTPUT:
{10 [1 2 3]}
{20 [4 5]}
*/
可以看出来,yaml.NewDecoder
返回的decoder
在调用Decode
方法的时候,每次都会从该文件中取出一个yaml文档进行解析,该文件中的所有文档都读取完成后,就会返回一个io.EOF
的error
,如果判断是该error
,就代表以及解析完毕。