将 YAML 中的映射字典键解析为结构体属性。

huangapple go评论81阅读模式
英文:

Unmarshal yaml map dict key to struct property

问题

我在这里搜索了一段时间,但没有找到一个合适的答案:

我正在尝试将YAML字典键解组到结构体的属性,而不是映射的键。
给定以下YAML:

commands:
    php:
        service: php
        bin: /bin/php
    node:
        service: node
        bin: /bin/node

我可以将其解组成如下的结构体:

type Config struct {
	Commands map[string]struct {
		Service string
		Bin     string
	}
}

但是我如何将其解组成如下的结构体:

type Config struct {
	Commands []struct {
		Name    string    // <-- 这应该是来自YAML的键(即php或node)
		Service string
		Bin     string
	}
}

提前感谢您的帮助。

英文:

I really searched a while here, but didn't found an adequate answer:

I am trying to unmarshall yaml dict keys onto a property of a struct rather than the key of a map.
Given this yaml

commands:
    php:
        service: php
        bin: /bin/php
    node:
        service: node
        bin: /bin/node

I am able to unmarshall this into a struct like this:

type Config struct {
	Commands map[string]struct {
		Service string
		Bin     string
	}
}

But how am I able to unmarshall it into a struct like this:

type Config struct {
	Commands []struct {
		Name    string    // <-- this should be key from the yaml (i.e. php or node)
		Service string
		Bin     string
	}
}

Thx in advance for the help

答案1

得分: 1

你可以编写一个自定义的解组器(unmarshaler),像这样(在Go Playground上):

package main

import (
	"fmt"

	"gopkg.in/yaml.v3"
)

var input []byte = []byte(`
commands:
    php:
        service: php
        bin: /bin/php
    node:
        service: node
        bin: /bin/node
`)

type Command struct {
	Service string
	Bin     string
}

type NamedCommand struct {
	Command
	Name string
}

type NamedCommands []NamedCommand

type Config struct {
	Commands NamedCommands
}

func (p *NamedCommands) UnmarshalYAML(value *yaml.Node) error {
	if value.Kind != yaml.MappingNode {
		return fmt.Errorf("`commands` must contain YAML mapping, has %v", value.Kind)
	}
	*p = make([]NamedCommand, len(value.Content)/2)
	for i := 0; i < len(value.Content); i += 2 {
		var res = &(*p)[i/2]
		if err := value.Content[i].Decode(&res.Name); err != nil {
			return err
		}
		if err := value.Content[i+1].Decode(&res.Command); err != nil {
			return err
		}
	}
	return nil
}

func main() {
	var f Config
	var err error
	if err = yaml.Unmarshal(input, &f); err != nil {
		panic(err)
	}
	for _, cmd := range f.Commands {
		fmt.Printf("%+v\n", cmd)
	}
}

我将命令数据分成了CommandNamedCommand,以使代码更简单,因为你可以直接调用Decode并为嵌入的Command结构提供值。如果所有内容都在同一个结构体中,你将需要手动将键映射到结构体字段。

英文:

You can write a custom unmarshaler, like this (on Go playground):

package main

import (
	&quot;fmt&quot;

	&quot;gopkg.in/yaml.v3&quot;
)

var input []byte = []byte(`
commands:
    php:
        service: php
        bin: /bin/php
    node:
        service: node
        bin: /bin/node
`)

type Command struct {
	Service string
	Bin     string
}

type NamedCommand struct {
	Command
	Name string
}

type NamedCommands []NamedCommand

type Config struct {
	Commands NamedCommands
}

func (p *NamedCommands) UnmarshalYAML(value *yaml.Node) error {
	if value.Kind != yaml.MappingNode {
		return fmt.Errorf(&quot;`commands` must contain YAML mapping, has %v&quot;, value.Kind)
	}
	*p = make([]NamedCommand, len(value.Content)/2)
	for i := 0; i &lt; len(value.Content); i += 2 {
		var res = &amp;(*p)[i/2]
		if err := value.Content[i].Decode(&amp;res.Name); err != nil {
			return err
		}
		if err := value.Content[i+1].Decode(&amp;res.Command); err != nil {
			return err
		}
	}
	return nil
}

func main() {
	var f Config
	var err error
	if err = yaml.Unmarshal(input, &amp;f); err != nil {
		panic(err)
	}
	for _, cmd := range f.Commands {
		fmt.Printf(&quot;%+v\n&quot;, cmd)
	}
}

I have split the command data into Command and NamedCommand to make the code simpler, since you can just call Decode giving the embedded Command struct for the values. If everything was in the same struct, you'd need to manually map keys to struct fields.

huangapple
  • 本文由 发表于 2022年12月28日 19:36:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/74939764.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定