英文:
How to unmarshal a yaml array?
问题
我有以下的YAML文件,如果我在在线YAML网站上验证它,它说它是有效的:
- {"foo": "1", "bar": "2"}
然后,我编写了一段代码来解析这个YAML文件中的值1
和2
,代码如下:
test.go:
package main
import "gopkg.in/yaml.v2"
import "fmt"
type Config struct {
Foo string
Bar string
}
type Configs struct {
Cfgs []Config `foobar`
}
func main() {
//var data = `
// foobar:
// - foo: 1
// bar: 2
//`
var data = `
- foo: 1
bar: 2
`
source := []byte("foobar:" + data)
var configs Configs
err := yaml.Unmarshal(source, &configs)
if err != nil {
fmt.Println("error: %v", err)
}
fmt.Printf("--- configs:\n%v\n\n", configs)
fmt.Println(configs.Cfgs[0].Foo)
fmt.Println(configs.Cfgs[0].Bar)
}
它正常工作如下:
shubuntu1@shubuntu1:~/20210810$ go run test.go
--- configs:
{[{1 2}]}
1
2
问题是什么?
你可以看到,我在这里做了一个变通的方法,即在原始的YAML之前添加了一个特殊的foobar
键,然后我可以使用type Configs struct
来解析它:
从
- foo: 1
bar: 2
到
foobar:
- foo: 1
bar: 2
那么,如果我不使用这个变通方法来添加前缀foobar:
,我该如何直接解析- {"foo": 1, "bar": 2}
?
英文:
I have next yaml, if I validate it in online yaml website, it said it's valid:
- {"foo": "1", "bar": "2"}
Then, I write a code to parse the value 1
and 2
from this yaml as next:
test.go:
package main
import "gopkg.in/yaml.v2"
import "fmt"
type Config struct {
Foo string
Bar string
}
type Configs struct {
Cfgs []Config `foobar`
}
func main() {
//var data = `
// foobar:
// - foo: 1
// bar: 2
//`
var data = `
- foo: 1
bar: 2
`
source := []byte("foobar:" + data)
var configs Configs
err := yaml.Unmarshal(source, &configs)
if err != nil {
fmt.Println("error: %v", err)
}
fmt.Printf("--- configs:\n%v\n\n", configs)
fmt.Println(configs.Cfgs[0].Foo)
fmt.Println(configs.Cfgs[0].Bar)
}
It works ok as next:
shubuntu1@shubuntu1:~/20210810$ go run test.go
--- configs:
{[{1 2}]}
1
2
What's the problem?
You could see I made a workaround here as next to add special foobar
key before the original yaml, then I could use type Configs struct
to unmarshal it:
From
- foo: 1
bar: 2
to
foobar:
- foo: 1
bar: 2
So, if I don't use the workaround to add a prefix foobar:
, how could I directly parse - {"foo": 1, "bar": 2}
?
答案1
得分: 5
由于您的YAML
数据是一个数组,因此将其解组为Config
结构的数组。
package main
import (
"fmt"
"gopkg.in/yaml.v2"
)
type Config struct {
Foo string
Bar string
}
func main() {
var configs []Config
var data = `
- foo: 1
bar: 2
`
err := yaml.Unmarshal([]byte(data), &configs)
if err != nil {
panic(err)
}
fmt.Println(configs)
}
输出:
[{1 2}]
在Go Playground上尝试。
英文:
Since your YAML
data is an array, unmarshal it to an array of Config
structure.
package main
import (
"fmt"
"gopkg.in/yaml.v2"
)
type Config struct {
Foo string
Bar string
}
func main() {
var configs []Config
var data = `
- foo: 1
bar: 2
`
err := yaml.Unmarshal([]byte(data), &configs)
if err != nil {
panic(err)
}
fmt.Println(configs)
}
Output:
[{1 2}]
Try on - Go Playground
答案2
得分: 1
由于问题已经得到解答,我想我可以在讨论中添加一些内容:
var data = `
- foo: 1
bar: 2
`
这里的data变量,按照你的写法,将包括每行开头的缩进。
这里的额外缩进将与所有实际的yaml数据一起传递给yaml.Unmarshal()
,这可能会导致问题,因为**gofmt
会将代码格式化为使用TAB作为缩进**,而在yaml中禁止使用TAB缩进(https://stackoverflow.com/a/19976827/7509248)。
如果你在yaml中使用TAB作为缩进,尝试解组时会抛出类似以下错误的异常:
yaml: line 1: found a tab character that violates indentation
最好的做法是从单独的文件中加载data
,以避免此类问题。
package main
import (
"fmt"
"io/ioutil"
"gopkg.in/yaml.v2"
)
type Config struct {
Foo string
Bar string
}
func main() {
var configs []Config
source, err := ioutil.ReadFile("config.yaml")
if err != nil {
fmt.Printf("failed reading config file: %v\n", err)
}
err = yaml.Unmarshal(source, &configs)
if err != nil {
fmt.Printf("error: %v\n", err)
}
fmt.Printf("config:\n%+v\n", configs)
}
config.yaml:
- foo: 1
bar: 2
输出:
config:
[{Foo:1 Bar:2}]
英文:
Since the question has already been answered, I thought I might add something to the discussion:
var data = `
- foo: 1
bar: 2
`
The data variable here, the way you wrote it, will include the indentation at the start of each line.
The extra indentation here WILL be passed into yaml.Unmarshal()
alongside all the actual yaml data, which can mess things up since gofmt
formats your code to use TAB as indentation and TAB indentation is forbidden in yaml (https://stackoverflow.com/a/19976827/7509248).
If you use tab as indentation in yaml, an error like this will be thrown when trying to unmarshal it:
yaml: line 1: found a tab character that violates indentation
Preferably, you want to load data
from a separate file to avoid such issue.
package main
import (
"fmt"
"io/ioutil"
"gopkg.in/yaml.v2"
)
type Config struct {
Foo string
Bar string
}
func main() {
var configs []Config
source, err := ioutil.ReadFile("config.yaml")
if err != nil {
fmt.Printf("failed reading config file: %v\n", err)
}
err = yaml.Unmarshal(source, &configs)
if err != nil {
fmt.Printf("error: %v\n", err)
}
fmt.Printf("config:\n%+v\n", configs)
}
config.yaml:
- foo: 1
bar: 2
output:
config:
[{Foo:1 Bar:2}]
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论