英文:
yaml multiple complex map keys as a struct
问题
我想将复杂的映射键解组为结构体:
YAML
unf:
item_meta:
source:
? id: "aa"
name: "bb"
: "some value"
结构体
type Source struct {
ID string `yaml:"id"`
Name string `yaml:"name"`
}
一切都按预期工作,直到我添加另一个键:
YAML 2
unf:
item_meta:
source:
? id: "012"
name: "Bill"
: "some value"
? id: "066"
name: "Bob"
: "another value"
我收到一个错误
"line xxx: mapping key "" already defined at line xxx"
我决定使用别名:
YAML 3
unf:
item_meta:
aliases:
- bill: &alias_bill
id: "012"
name: "Bill"
- bob: &alias_bob
id: "066"
name: "Bob"
source:
? *alias_bill
: "some value"
? *alias_bob
name: "Bob"
: "another value"
它解决了问题!但是我们在堆栈中使用hiera server
,而hiera
返回已经替换的配置文件内容,所以我最终得到YAML 2版本。
有没有办法解决这个问题?配置hiera server
不是一个选项。
英文:
I want to unmarshal complex map key into struct:
YAML
unf:
item_meta:
source:
? id: "aa"
name: "bb"
: "some value"
Struct
type Source struct {
ID string `yaml:"id"`
Name string `yaml:"name"`
}
Everything works as expected until I add another key:
YAML 2
unf:
item_meta:
source:
? id: "012"
name: "Bill"
: "some value"
? id: "066"
name: "Bob"
: "another value"
I got an error
> "line xxx: mapping key "" already defined at line xxx"
I decided to use aliases:
YAML 3
unf:
item_meta:
aliases:
- bill: &alias_bill
id: "012"
name: "Bill"
- bob: &alias_bob
id: "066"
name: "Bob"
source:
? *alias_bill
: "some value"
? *alias_bob
name: "Bob"
: "another value"
It fixed the problem! BUT we use hiera server
in our stack AND hiera
returns contents of a config file already substituted so I end up with YAML 2 version.
Any ideas on how to fix the problem? To config the hiera server
is not an option.
Go playground
答案1
得分: 1
我的解决方案主要基于larsks的这个问题。
想法是找到具有重复映射键的节点,并从映射节点的值节点创建自定义值。
func fixYamlNode(node *yaml.Node) {
if node.Kind == yaml.MappingNode {
length := len(node.Content)
for i := 0; i < length; i += 2 {
nodes := make([]*yaml.Node, 0)
nodes = append(nodes, node.Content[i])
for j := i + 2; j < length; j += 2 {
nj := node.Content[j]
if nodes[0].Kind == nj.Kind && nodes[0].Value == nj.Value {
nodes = append(nodes, nj)
}
}
if len(nodes) == 1 {
continue
}
fillMapValue(nodes)
}
for i := 1; i < length; i += 2 {
valueNode := node.Content[i]
fixYamlNode(valueNode)
}
}
}
func fillMapValue(nodes []*yaml.Node) {
for _, node := range nodes {
length := len(node.Content)
for i := 0; i < length; i += 2 {
node.Value = fmt.Sprintf("%s %s", node.Value, node.Content[i+1].Value)
}
}
}
英文:
My solution mostly was based on this issue @larsks
The idea was to find nodes with duplicate map keys and to create a custom value from value nodes of THE map node.
func fixYamlNode(node *yaml.Node) {
if node.Kind == yaml.MappingNode {
length := len(node.Content)
for i := 0; i < length; i += 2 {
nodes := make([]*yaml.Node, 0)
nodes = append(nodes, node.Content[i])
for j := i + 2; j < length; j += 2 {
nj := node.Content[j]
if nodes[0].Kind == nj.Kind && nodes[0].Value == nj.Value {
nodes = append(nodes, nj)
}
}
if len(nodes) == 1 {
continue
}
fillMapValue(nodes)
}
for i := 1; i < length; i += 2 {
valueNode := node.Content[i]
fixYamlNode(valueNode)
}
}
}
func fillMapValue(nodes []*yaml.Node) {
for _, node := range nodes {
length := len(node.Content)
for i := 0; i < length; i += 2 {
node.Value = fmt.Sprintf("%s %s", node.Value, node.Content[i+1].Value)
}
}
}
答案2
得分: 0
这是go-yaml中的一个错误。请参考这些行:
ni := n.Content[i]
for j := i + 2; j < l; j += 2 {
nj := n.Content[j]
if ni.Kind == nj.Kind && ni.Value == nj.Value {
d.terrors = append(d.terrors, fmt.Sprintf("line %d: mapping key %#v already defined at line %d", nj.Line, nj.Value, ni.Line))
}
}
这段代码用于检查重复的键。对于映射中的每个键(ni
),它会遍历所有后续的键(nj
),并检查它们是否具有相同的Kind和相同的Value。这是错误的,因为Value
仅针对标量键设置,所以一旦你有两个键是映射类型,即使键是不同的,这个错误也会触发,因为代码不会比较键的内容,只会比较它们的值(对于非标量节点,值将为空字符串)。
我建议你在go-yaml上提一个问题。
英文:
This is an error in go-yaml. See these lines:
ni := n.Content[i]
for j := i + 2; j < l; j += 2 {
nj := n.Content[j]
if ni.Kind == nj.Kind && ni.Value == nj.Value {
d.terrors = append(d.terrors, fmt.Sprintf("line %d: mapping key %#v already defined at line %d", nj.Line, nj.Value, ni.Line))
}
}
This code checks for duplicate keys. For each key in the mapping (ni
), it goes through all succeeding keys (nj
) and checks whether they have the same Kind and the same Value. This is wrong, since Value
is only set for scalar keys, so as soon as you have two keys that are mappings, this error fires even though the keys are different, because the code does not compare the key's content, only their Values (which will be the empty strings for non-scalar nodes).
I suggest you open an issue with go-yaml.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论