How to parse YAML with dynamic key in Golang

前端 未结 1 1427
余生分开走
余生分开走 2020-12-17 19:23

I am trying to parse a YAML file with Go. The problem is that the keys in the YAML file might not always be the same. This is to do API versioning so the user can define the

相关标签:
1条回答
  • 2020-12-17 20:02

    First, you are trying to parse the root as an Environment, but its actual type is map[string]Environment. Second, you are going to need a custom Unmarshaler if you want to keep that type structure. Something like this:

    package main
    
    import (
        "fmt"
    
        "gopkg.in/yaml.v2"
    )
    
    var data = `
    ---
    development:
      skip-header-validation: true
      V1:
        current: "1.0.0"
        mime_types:
          - application/vnd.company.jk.identity+json;
          - application/vnd.company.jk.user+json;
          - application/vnd.company.jk.role+json;
          - application/vnd.company.jk.scope+json;
          - application/vnd.company.jk.test+json;
        skip-mime-type-validation: true
        skip-version-validation: true
      V2:
        current: "2.0.0"
        mime_types:
          - application/vnd.company.jk.identity+json;
          - application/vnd.company.jk.user+json;
          - application/vnd.company.jk.role+json;
          - application/vnd.company.jk.scope+json;
          - application/vnd.company.jk.test+json;
    
    `
    
    type MajorVersion struct {
        Current                string   `yaml:"current"`
        MimeTypes              []string `yaml:"mime_types"`
        SkipVersionValidation  bool     `yaml:"skip-version-validation"`
        SkipMimeTypeValidation bool     `yaml:"skip-mime-type-validation"`
    }
    
    type Environment struct {
        SkipHeaderValidation bool
        Versions             map[string]MajorVersion
    }
    
    func (e *Environment) UnmarshalYAML(unmarshal func(interface{}) error) error {
        var params struct {
            SkipHeaderValidation bool `yaml:"skip-header-validation"`
        }
        if err := unmarshal(&params); err != nil {
            return err
        }
        var versions map[string]MajorVersion
        if err := unmarshal(&versions); err != nil {
            // Here we expect an error because a boolean cannot be converted to a
            // a MajorVersion
            if _, ok := err.(*yaml.TypeError); !ok {
                return err
            }
        }
        e.SkipHeaderValidation = params.SkipHeaderValidation
        e.Versions = versions
        return nil
    }
    
    func main() {
        var e map[string]Environment
        if err := yaml.Unmarshal([]byte(data), &e); err != nil {
            fmt.Println(err.Error())
        }
        fmt.Printf("%#v\n", e)
    }
    

    Output (after using makeup):

    map[string]main.Environment{
        "development": {
            SkipHeaderValidation: true,
            Versions:             {
                "V2": {
                    Current:                "2.0.0",
                    MimeTypes:              {"application/vnd.company.jk.identity+json;", "application/vnd.company.jk.user+json;", "application/vnd.company.jk.role+json;", "application/vnd.company.jk.scope+json;", "application/vnd.company.jk.test+json;"},
                    SkipVersionValidation:  false,
                    SkipMimeTypeValidation: false,
                },
                "V1": {
                    Current:                "1.0.0",
                    MimeTypes:              {"application/vnd.company.jk.identity+json;", "application/vnd.company.jk.user+json;", "application/vnd.company.jk.role+json;", "application/vnd.company.jk.scope+json;", "application/vnd.company.jk.test+json;"},
                    SkipVersionValidation:  true,
                    SkipMimeTypeValidation: true,
                },
            },
        },
    }
    
    0 讨论(0)
提交回复
热议问题