首页 > 解决方案 > 从 YAML 文件中读取多个文档并使用 go yaml v3 编组它们

问题描述

我正在尝试使用gopkg.in/yaml.v3读取包含多个 YAML 文档的文件,然后将每个单独的文档编组回 YAML。我的示例输入如下所示:

name: doc1
---
name: doc2
---
name: doc3

我能够很好地解组文件,但是在尝试编组单个文档时遇到了意外错误。我的代码如下所示:

package main

import (
    "errors"
    "fmt"
    "io"

    "os"

    "gopkg.in/yaml.v3"
)

func main() {
    reader := io.Reader(os.Stdin)
    dec := yaml.NewDecoder(reader)

    for {
        var node yaml.Node
        err := dec.Decode(&node)
        if errors.Is(err, io.EOF) {
            break
        }
        if err != nil {
            panic(err)
        }

        content, err := yaml.Marshal(node)
        if err != nil {
            panic(err)
        }

        fmt.Printf("Found a doc\n\n%s\n", content)
    }
}

使用示例输入运行此代码会导致:

panic: yaml: expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, but got document start

goroutine 1 [running]:
main.main()
        /home/lars/projects/operate-first/halberd/main.go:31 +0x451

该代码似乎正确解析了文档;如果我将其替换为:

package main

import (
    "errors"
    "fmt"
    "io"

    "os"

    "gopkg.in/yaml.v3"
)

func main() {
    reader := io.Reader(os.Stdin)
    dec := yaml.NewDecoder(reader)

    for {
        var node yaml.Node
        err := dec.Decode(&node)
        if errors.Is(err, io.EOF) {
            break
        }
        if err != nil {
            panic(err)
        }

        fmt.Printf("Found a doc\n")
    }
}

我最终得到了我的期望:

Found a doc
Found a doc
Found a doc

这个问题只会在编组时出现。我是否正确使用了 v3 api?

标签: goyaml

解决方案


您的代码中有一个小错误。
应该是content, err := yaml.Marshal(&node)。你错过了&.
这行得通,

package main

import (
    "errors"
    "fmt"
    "io"

    "os"

    "gopkg.in/yaml.v3"
)

func main() {
    reader := io.Reader(os.Stdin)
    dec := yaml.NewDecoder(reader)

    for {
        var node yaml.Node
        err := dec.Decode(&node)
        if errors.Is(err, io.EOF) {
            break
        }
        if err != nil {
            panic(err)
        }

        content, err := yaml.Marshal(&node)
        if err != nil {
            panic(err)
        }

        fmt.Printf("Found a doc\n\n%s\n", content)
    }
}

的文档yaml.Marshal说,

Marshal 将提供的值序列化到 YAML 文档中。生成文档的结构将反映值本身的结构。映射和指针(指向 struct、string、int 等)被接受为 in 值。

来源:https ://pkg.go.dev/gopkg.in/yaml.v2#Marshal

正如文档所说,由于您正在尝试编组yaml.Node这是一个结构,因此您必须将指针传递给结构而不是值本身。


推荐阅读