【问题标题】:How to parse YAML with dynamic key in Golang如何在 Golang 中使用动态键解析 YAML
【发布时间】:2015-11-15 19:29:25
【问题描述】:

我正在尝试使用 Go 解析 YAML 文件。问题是 YAML 文件中的键可能并不总是相同的。这是为了进行 API 版本控制,以便用户可以定义他们支持的版本。例如 V1、V2、V3 等。它们不需要按顺序排列,可以省略它们不支持的版本,即 V0、V2、V5 等。

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        `yaml:"skip-header-validation"`
  Version               map[string]MajorVersion
}

func main() {
  e := Environment{}

  yaml.Unmarshal([]byte(data), &e)
  fmt.Println(e)
}

我看到了similar question asked here

这是在顶层,我还没有完全弄清楚如何从结构内部做到这一点。

【问题讨论】:

    标签: go yaml


    【解决方案1】:

    首先,您尝试将根解析为Environment,但它的实际类型是map[string]Environment。其次,如果您想保留该类型结构,您将需要一个自定义的Unmarshaler。像这样的:

    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)
    }
    

    输出(使用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,
                },
            },
        },
    }
    

    【讨论】:

    • 哇,好人,谢谢。很酷,看看这是如何在 go 中完成的。有趣的是,有时您需要多少代码来解析 yaml!
    猜你喜欢
    • 2018-05-29
    • 2017-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-23
    • 1970-01-01
    • 2019-02-13
    • 2018-12-21
    相关资源
    最近更新 更多