简体   繁体   English

读取文件中的多个 yaml

[英]Read multiple yamls in a file

How does one parse multiple yamls in a file similar to how kubectl does it?如何解析文件中的多个 yaml 类似于 kubectl 的方式?

example.yaml例子.yaml

---
a: Easy!
b:
  c: 0
  d: [1, 2]
---
a: Peasy!
b:
  c: 1000
  d: [3, 4]

There's a difference in behavior between gopkg.in/yaml.v2 and gopkg.in/yaml.v3: gopkg.in/yaml.v2 和 gopkg.in/yaml.v3 之间的行为存在差异:

V2: https://play.golang.org/p/XScWhdPHukO V3: https://play.golang.org/p/OfFY4qH5wW2 V2: https : //play.golang.org/p/XScWhdPHukO V3: https : //play.golang.org/p/OfFY4qH5wW2

Both implementations produce an incorrect result IMHO but V3 is apparently slightly worse.两种实现都会产生不正确的结果恕我直言,但 V3 显然稍差一些。

There's a workaround.有一个解决方法。 If you slightly change code in the accepted answer, it works correctly and in the same fashion with both versions of yaml package: https://play.golang.org/p/r4ogBVcRLCb如果您稍微更改了已接受答案中的代码,它可以在两个版本的 yaml 包中以相同的方式正常工作: https : //play.golang.org/p/r4ogBVcRLCb

Solution I found using gopkg.in/yaml.v2 :我发现使用gopkg.in/yaml.v2解决方案:

package main

import (
    "bytes"
    "fmt"
    "io/ioutil"
    "log"
    "path/filepath"

    "gopkg.in/yaml.v2"
)

type T struct {
        A string
        B struct {
                RenamedC int   `yaml:"c"`
                D        []int `yaml:",flow"`
        }
}

func main() {
    filename, _ := filepath.Abs("./example.yaml")
    yamlFile, err := ioutil.ReadFile(filename)
    if err != nil {
        panic(err)
    }

    r := bytes.NewReader(yamlFile)

    dec := yaml.NewDecoder(r)

    var t T
    for dec.Decode(&t) == nil {

      fmt.Printf("a :%v\nb :%v\n", t.A, t.B)

    }
}

Current gopkg.in/yaml.v3 Deocder produces quite correct result, you just need to pay attention on creating new structure for each document and check it was parsed correctly (with nil check), and handle EOF error correctly:当前gopkg.in/yaml.v3 Deocder产生了相当正确的结果,您只需要注意为每个文档创建新结构并检查它是否被正确解析(使用nil检查),并正确处理EOF错误:

package main

import "fmt"
import "gopkg.in/yaml.v3"
import "os"
import "errors"
import "io"

type Spec struct {
    Name string `yaml:"name"`
}

func main() {
    f, err := os.Open("spec.yaml")
    if err != nil {
        panic(err)
    }
    d := yaml.NewDecoder(f)
    for {
        // create new spec here
        spec := new(Spec)
        // pass a reference to spec reference
        err := d.Decode(&spec)
        // check it was parsed
        if spec == nil {
            continue
        }
        // break the loop in case of EOF
        if errors.Is(err, io.EOF) {
            break
        }
        if err != nil {
            panic(err)
        }
        fmt.Printf("name is '%s'\n", spec.Name)
    }
}

Test file spec.yaml :测试文件spec.yaml

---
name: "doc first"
---
name: "second"
---
---
name: "skip 3, now 4"
---

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM