从YAML文件中读取多个文档,并使用Go YAML v3进行编组。

huangapple go评论96阅读模式
英文:

Reading multiple documents from a YAML file and marshaling them with 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?

英文:

I'm trying to use gopkg.in/yaml.v3 to read a file containing
multiple YAML documents, and then marshal each individual document
back into YAML. My sample input looks like:

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

I'm able to unmarshal the file just fine, but I run into unexpected
errors when trying to marshal the individual documents. My code looks
like:

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)
	}
}

Running this code with the sample input results in:

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

The code seems to be parsing the document correctly; if I replace it
with:

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")
	}
}

I end up with what I expect:

Found a doc
Found a doc
Found a doc

The problem only crops up when marshaling. Am I correctly using the v3 api?

答案1

得分: 1

你的代码中有一个小错误。应该是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文档。生成的文档的结构将反映值本身的结构。接受映射和指针(指向结构、字符串、整数等)作为输入值。

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

由于你尝试对yaml.Node进行序列化,而它是一个结构体,所以你必须传递结构体的指针而不是值本身,正如文档所述。

英文:

There was a small mistake in your code.
It should be content, err := yaml.Marshal(&node). You missed the &.
This works,

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)
    }
}

The docs for yaml.Marshal says,
> Marshal serializes the value provided into a YAML document. The structure of the generated document will reflect the structure of the value itself. Maps and pointers (to struct, string, int, etc) are accepted as the in value.

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

Since you are trying to marshal yaml.Node which is a struct, you must pass the pointer to the struct and not the value itself, as the docs say.

huangapple
  • 本文由 发表于 2021年5月19日 23:39:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/67606439.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定