英文:
Go unmarshal yaml and preserve order
问题
假设我有以下的 YAML 文件:
key1:
- "Value1"
- "Value2"
key2:
- "Value3"
- "Value4"
我想在 Go 中对其进行解析。我可以让 Go 自己决定方案的样子并将其打印出来。
m := make(map[interface{}]interface{})
err := yaml.Unmarshal(yaml_file, &m)
fmt.Println(m)
这将打印出类似以下的内容:
map[key1:[Value1 Value2] key2:[Value3 Value4]]
但是,映射是无序的。对我来说,顺序非常重要,而且我也不想丢失键。
我不能只是创建一个结构体,然后尝试将 YAML 文件解析为该结构体的切片...
type Element struct {
Key string
Value interface{}
}
t := []Element{}
err := yaml.Unmarshal(yaml_file, &t)
if err != nil {
log.Fatalf("error: %v", err)
}
会打印出 error: yaml: unmarshal errors: line 2: cannot unmarshal !!map into []Element
。
没有字段标签可以告诉 YAML 解析器将 Key 属性填充为 YAML 键。
除了编写自己的解码器之外,是否有其他方法呢?
英文:
Let's say I have the following yaml file:
key1:
- "Value1"
- "Value2"
key2:
- "Value3"
- "Value4"
And I want to unmarshal that in Go. I can let Go decide what the scheme should look like and print it out.
m := make(map[interface{}]interface{})
err := yaml.Unmarshal(yaml_file, &m)
fmt.Prinf(m)
This will print something like this:
map[key1:[Value1 Value2] key2:[Value3 Value4]]
But maps are unordered. The order is very important for me tho and I also don't want to loose the keys.
I can't just create a struct and try to unmarshal the yaml file to a slice of that struct...
type Element struct {
Key string
Value interface{}
}
t := []Element{}
err := yaml.Unmarshal(yaml_file, &t)
if err != nil {
log.Fatalf("error: %v", err)
}
Will print error: yaml: unmarshal errors: line 2: cannot unmarshal !!map into []Element
There is no field tag to tell the yaml parser to fill the Key property with the yaml key.
Is there a different way than writing my own decoder?
答案1
得分: 4
刚刚在我准备发布问题之前找到了答案。
答案是MapSlice!你需要从gopkg
导入yaml.v2
。(截至我写这篇文章时,MapSlices
似乎还没有在yaml.v3中实现)
MapSlices
完全实现了我所需要的,并由多个MapItem
组成。
type MapItem struct {
Key, Value interface{}
}
现在只需将其解组为MapSlice。如果你想使用自己的类型进行操作,你总是可以进行转换,但可能需要进行一些类型转换。
m := yaml.MapSlice{}
yaml.Unmarshal(yaml_file, &m)
t := []Element{}
for _, item := range m {
t = append(t, Element{item.Key.(string), item.Value})
}
英文:
Just found the answer right before I wanted to post the question.
The answer is MapSlice!
You need to import yaml.v2
from gopkg
. (As of writing this MapSlices don't seem to be implemented in yaml.v3 yet)
MapSlices
implement exactly what I needed and are made of a number of MapItem
s.
type MapItem struct {
Key, Value interface{}
}
So now just unmarshal to a MapSlice. If you want to work with your own types you can always convert it but might need to do some typecasting.
m := yaml.MapSlice{}
yaml.Unmarshal(yaml_file, &m)
t := []Element{}
for _, item := range m {
t = append(t, Element{item.Key.(string), item.Value})
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论