当前位置: 首页 > 知识库问答 >
问题:

基于YAML字段将YAML解组为不同的结构

徐杰
2023-03-14

我正在尝试将以下YAML数据分解为Go结构。

数据采用以下格式:

fetchers:
- type: "aws"
  config:
    omega: "lul"
- type: "kubernetes"
  config: 
    foo: "bar"

根据类型字段,我想确定是否将配置字段解组到awsConfig或kubernetesConfig结构中。

我当前的代码如下(使用“gopkg.in/yaml.v2”):

type kubernetesConfig struct {
    foo string `yaml:"foo"`
}
type awsConfig struct {
    omega string `yaml:"omega"`
}

var c struct {
    Fetchers []struct {
        Type   string      `yaml:"type"`
        Config interface{} `yaml:"config"`
    } `yaml:"fetchers"`
}

err := yaml.Unmarshal(data, &c)
if err != nil {
    log.Fatal(err)
}
for _, val := range c.Fetchers {
    switch val.Type {
    case "kubernetes":
        conf := val.Config.(kubernetesConfig)
        fmt.Println(conf.foo)
    case "aws":
        conf := val.Config.(awsConfig)
        fmt.Println(conf.omega)
    default:
        log.Fatalf("No matching type, was type %v", val.Type)
    }
}

操场代码:https://go.dev/play/p/klxOoHMCtnG

目前它被解组为 map[接口 {}]接口 {},无法转换为上述结构之一。错误:panic:接口转换:接口 {}
是映射[接口 {}]接口 {},而不是 main.awsConfig \

我是否必须使用自定义UnmarshalYAML函数实现YAML包的Unmarshaler接口才能完成此操作?

共有2个答案

空正豪
2023-03-14

这种类型的任务(您希望延迟解组)与json非常相似。RawMessage适用于这样的示例。

yaml 包没有类似的 RawMessage 机制 - 但这种技术可以很容易地复制,如下所述:

type RawMessage struct {
    unmarshal func(interface{}) error
}

func (msg *RawMessage) UnmarshalYAML(unmarshal func(interface{}) error) error {
    msg.unmarshal = unmarshal
    return nil
}

// call this method later - when we know what concrete type to use
func (msg *RawMessage) Unmarshal(v interace{}) error {
    return msg.unmarshal(v)
}

因此,要在您的案例中利用这一点:

var fs struct {
    Configs []struct {
        Type   string     `yaml:"type"`
        Config RawMessage `yaml:"config"` // delay unmarshaling
    } `yaml:"fetchers"`
}

err = yaml.Unmarshal([]byte(data), &fs)
if err != nil {
    return
}

根据配置“类型”(< code>aws或< code>kubernetes),您最终可以将< code>RawMessage解组为正确的具体类型:

aws := awsConfig{} // concrete type
err = c.Config.Unmarshal(&aws)

或:

k8s := kubernetesConfig{} // concrete type
err = c.Config.Unmarshal(&k8s)

这里的工作示例:https://go.dev/play/p/wsykOXNWk3H

邢嘉祯
2023-03-14

通过实现解组器接口找到了解决方案:

type Fetcher struct {
    Type   string      `yaml:"type"`
    Config interface{} `yaml:"config"`
}

// Interface compliance
var _ yaml.Unmarshaler = &Fetcher{}

func (f *Fetcher) UnmarshalYAML(unmarshal func(interface{}) error) error {
    var t struct {
        Type string `yaml:"type"`
    }
    err := unmarshal(&t)
    if err != nil {
        return err
    }
    f.Type = t.Type
    switch t.Type {
    case "kubernetes":
        var c struct {
            Config kubernetesConfig `yaml:"config"`
        }
        err := unmarshal(&c)
        if err != nil {
            return err
        }
        f.Config = c.Config
    case "aws":
        var c struct {
            Config awsConfig `yaml:"config"`
        }
        err := unmarshal(&c)
        if err != nil {
            return err
        }
        f.Config = c.Config
    }
    return nil
}
 类似资料:
  • 问题内容: 我正在尝试将YAML数据解析为字符串: 由于某种原因,config是一个空结构&{}。 问题答案: 您的结构的字段未导出。导出它们,它将起作用。

  • 问题内容: 我正在尝试解组以下YAML(使用gopkg.in/yaml.v2): 使用以下代码: 但这给了我以下错误: 顶级属性是动态的,因此我需要将它们解析为字符串,结构中的所有其他键将始终相同,因此这些部分的结构也是如此。我该如何解析? (完整代码位于https://github.com/tirithen/unit- conversion/blob/master/convert.go#L84

  • 本文向大家介绍yaml 基本的YAML类型,包括了yaml 基本的YAML类型的使用技巧和注意事项,需要的朋友参考一下 示例            

  • 主要内容:创建YAML文件的规则,YAML文件的基本组件,YAML基本要素简介经过前一节的学习,现在已经了解了YAML及其功能,下面通过语法和其他操作了解它的基础知识。 请记住,YAML包含人类可读的结构化格式。 创建YAML文件的规则 在YAML中创建文件时,应该记住以下基本规则 - YAML区分大小写。 这些文件使用作为扩展名。 YAML在创建YAML文件时不允许使用制表符,只允许使用空格。 YAML文件的基本组件 YAML的基本组成部分如下所述 - 常规块格式 此块格

  • 我有一个GKE集群。 我使用从本地机器应用以下YAML: 申请了。很好。✅ 然后我用从集群中获取YAML,它返回了这个: 提前谢谢你。 我一直在想这件事。感谢您在这里提供的建议和建议。

  • 问题内容: 我想将此yaml字符串转换为json,因为源数据是动态的,所以我无法将其映射到结构: 然后我想再次将该接口转换为json字符串: 但是发生错误: 问题答案: 前言: 我优化并改进了以下解决方案,并将其作为库发布在这里:。以下功能可作为。 问题在于,如果您使用最通用的类型来解组,则包用于解组键- 值对的默认类型将是。 第一个想法是使用: 但是,如果yaml配置的深度大于一,则此尝试将失败