在Golang中,有没有一种方法可以向现有的YAML文档中添加一个YAML节点?

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

Is there a way to add a yaml node to an existing yaml document in golang?

问题

我正在使用goyaml库读取一个yaml文件。我打算修改其中的一些条目,并在要添加的键不存在时添加一个条目。

例如:

原始的yaml文件

root:
  entry1: val1

修改1个条目并添加1个条目的目标yaml文件

root:
 entry1: valUpdated
 entry2: newkey added

我找不到任何可以允许我向yaml添加节点的库。

谢谢你的帮助。

英文:

I am reading a yaml file with goyaml lib. I intend to modify some of its entries and add an entry if the key to be added is not already present.

e.g.

original yaml

root:
  entry1: val1

1 mod and 1 add target yaml

root:
 entry1: valUpdated
 entry2: newkey added

I cannot find any yaml lib which can allow me to add a node to yaml.

thanks for your help

答案1

得分: 1

你可以使用go-yaml来实现这个功能,如果你将其解组为yaml.Node

package main

import (
	"os"

	"gopkg.in/yaml.v3"
)

var input = []byte(`root:
  entry1: val1`)

func main() {
	var document yaml.Node
	if err := yaml.Unmarshal(input, &document); err != nil {
		panic(err)
	}
	data := document.Content[0]
	var rootVal *yaml.Node
	for i := 0; i < len(data.Content); i += 2 {
		node := data.Content[i]
		if node.Kind == yaml.ScalarNode && node.Value == "root" {
			rootVal = data.Content[i+1]
			break
		}
	}
	if rootVal == nil {
		panic("root key missing")
	}

	found := false
	for i := 0; i < len(rootVal.Content); i += 2 {
		node := rootVal.Content[i]
		if node.Kind != yaml.ScalarNode {
			continue
		}
		switch node.Value {
		case "entry1":
			rootVal.Content[i+1].SetString("valUpdated")
		case "entry2":
			found = true
		}
	}
	if !found {
		var key, value yaml.Node
		key.SetString("entry2")
		value.SetString("newkey added")
		rootVal.Content = append(rootVal.Content, &key, &value)
	}
	out, err := yaml.Marshal(data)
	if err != nil {
		panic(err)
	}
	os.Stdout.Write(out)
}

输出结果为:

root:
    entry1: valUpdated
    entry2: newkey added

Playground链接

Unmarshal函数将返回一个带有根节点作为唯一内容节点的文档节点。Marshal函数期望根节点作为数据,因此你需要将data传递给它,而不是document。我不太确定为什么API设计成这样。

英文:

You can do this with go-yaml if you unmarshal to yaml.Node:

package main

import (
	&quot;os&quot;

	&quot;gopkg.in/yaml.v3&quot;
)

var input = []byte(`root:
  entry1: val1`)

func main() {
	var document yaml.Node
	if err := yaml.Unmarshal(input, &amp;document); err != nil {
		panic(err)
	}
	data := document.Content[0]
	var rootVal *yaml.Node
	for i := 0; i &lt; len(data.Content); i += 2 {
		node := data.Content[i]
		if node.Kind == yaml.ScalarNode &amp;&amp; node.Value == &quot;root&quot; {
			rootVal = data.Content[i+1]
			break
		}
	}
	if rootVal == nil {
		panic(&quot;root key missing&quot;)
	}

	found := false
	for i := 0; i &lt; len(rootVal.Content); i += 2 {
		node := rootVal.Content[i]
		if node.Kind != yaml.ScalarNode {
			continue
		}
		switch node.Value {
		case &quot;entry1&quot;:
			rootVal.Content[i+1].SetString(&quot;valUpdated&quot;)
		case &quot;entry2&quot;:
			found = true
		}
	}
	if !found {
		var key, value yaml.Node
		key.SetString(&quot;entry2&quot;)
		value.SetString(&quot;newkey added&quot;)
		rootVal.Content = append(rootVal.Content, &amp;key, &amp;value)
	}
	out, err := yaml.Marshal(data)
	if err != nil {
		panic(err)
	}
	os.Stdout.Write(out)
}

output:

root:
    entry1: valUpdated
    entry2: newkey added

Playground link

Unmarshal gets you a document node with the root node as sole content node. Marshal expects the root node as data, so you feed data instead of document into it. I am not really sure why the API is like that.

huangapple
  • 本文由 发表于 2022年10月2日 07:22:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/73922373.html
匿名

发表评论

匿名网友

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

确定