英文:
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
Unmarshal
函数将返回一个带有根节点作为唯一内容节点的文档节点。Marshal
函数期望根节点作为数据,因此你需要将data
传递给它,而不是document
。我不太确定为什么API设计成这样。
英文:
You can do this with go-yaml if you unmarshal to 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)
}
output:
root:
entry1: valUpdated
entry2: newkey added
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论