Kir*_*ill 5 parsing yaml marshalling go unmarshalling
我有一个yaml文件,其中一个字段可以由一种可能的结构表示。为了简化代码和 yaml 文件,假设我有这些 yaml 文件:
kind: "foo"
spec:
fooVal: 4
Run Code Online (Sandbox Code Playgroud)
kind: "bar"
spec:
barVal: 5
Run Code Online (Sandbox Code Playgroud)
这些用于解析的结构:
type Spec struct {
Kind string `yaml:"kind"`
Spec interface{} `yaml:"spec"`
}
type Foo struct {
FooVal int `yaml:"fooVal"`
}
type Bar struct {
BarVal int `yaml:"barVal"`
}
Run Code Online (Sandbox Code Playgroud)
我知道我可以map[string]interface{}用作一种Spec字段。但是真实的例子更复杂,并且涉及更多可能的结构类型,不仅仅是Fooand Bar,这就是为什么我不喜欢解析spec到字段中。
我找到了一种解决方法:将 yaml 解组为中间结构,然后检查kind字段,并将map[string]interface{}字段编组为 yaml,并将其解组为具体类型:
var spec Spec
if err := yaml.Unmarshal([]byte(src), &spec); err != nil {
panic(err)
}
tmp, _ := yaml.Marshal(spec.Spec)
if spec.Kind == "foo" {
var foo Foo
yaml.Unmarshal(tmp, &foo)
fmt.Printf("foo value is %d\n", foo.FooVal)
}
if spec.Kind == "bar" {
tmp, _ := yaml.Marshal(spec.Spec)
var bar Bar
yaml.Unmarshal(tmp, &bar)
fmt.Printf("bar value is %d\n", bar.BarVal)
}
Run Code Online (Sandbox Code Playgroud)
但它需要额外的步骤并消耗更多的内存(真实的 yaml 文件可能比示例中的更大)。是否存在一些更优雅的方法来将 yaml 动态解组为一组有限的结构?
更新:我正在使用github.com/go-yaml/yaml v2.1.0Yaml 解析器。
为了与您一起使用,yaml.v2您可以执行以下操作:
type yamlNode struct {
unmarshal func(interface{}) error
}
func (n *yamlNode) UnmarshalYAML(unmarshal func(interface{}) error) error {
n.unmarshal = unmarshal
return nil
}
type Spec struct {
Kind string `yaml:"kind"`
Spec interface{} `yaml:"-"`
}
Run Code Online (Sandbox Code Playgroud)
func (s *Spec) UnmarshalYAML(unmarshal func(interface{}) error) error {
type S Spec
type T struct {
S `yaml:",inline"`
Spec yamlNode `yaml:"spec"`
}
obj := &T{}
if err := unmarshal(obj); err != nil {
return err
}
*s = Spec(obj.S)
switch s.Kind {
case "foo":
s.Spec = new(Foo)
case "bar":
s.Spec = new(Bar)
default:
panic("kind unknown")
}
return obj.Spec.unmarshal(s.Spec)
}
Run Code Online (Sandbox Code Playgroud)
https://play.golang.org/p/Ov0cOaedb-x
为了与您一起使用,yaml.v3您可以执行以下操作:
type Spec struct {
Kind string `yaml:"kind"`
Spec interface{} `yaml:"-"`
}
Run Code Online (Sandbox Code Playgroud)
func (s *Spec) UnmarshalYAML(n *yaml.Node) error {
type S Spec
type T struct {
*S `yaml:",inline"`
Spec yaml.Node `yaml:"spec"`
}
obj := &T{S: (*S)(s)}
if err := n.Decode(obj); err != nil {
return err
}
switch s.Kind {
case "foo":
s.Spec = new(Foo)
case "bar":
s.Spec = new(Bar)
default:
panic("kind unknown")
}
return obj.Spec.Decode(s.Spec)
}
Run Code Online (Sandbox Code Playgroud)
https://play.golang.org/p/ryEuHyU-M2Z
| 归档时间: |
|
| 查看次数: |
511 次 |
| 最近记录: |