首页 > 文章列表 > 使用解析器将YAML解组,将字典键映射到对象属性

使用解析器将YAML解组,将字典键映射到对象属性

381 2024-02-17
问题内容

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

我正在尝试将 yaml dict 键解组到结构的属性而不是映射的键上。 给定这个 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    // <-- this should be key from the yaml (i.e. php or node)
        Service string
        Bin     string
    }
}

提前感谢您的帮助


正确答案


您可以编写一个自定义解组器,如下所示(在 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("%+vn", cmd)
    }
}

我已将命令数据拆分为 commandnamedcommand 以使代码更简单,因为您只需调用 decode 即可提供嵌入的 command 结构体的值。如果所有内容都在同一个结构中,则需要手动将键映射到结构字段。