【问题标题】:Go parse yaml file去解析yaml文件
【发布时间】:2015-04-25 06:54:07
【问题描述】:

我正在尝试使用 Go 解析 yaml 文件。不幸的是,我无法弄清楚如何。我的yaml文件是这样的:

---
firewall_network_rules:
  rule1:
    src:       blablabla-host
    dst:       blabla-hostname
...

我有这个 Go 代码,但它不起作用:

package main

import (
    "fmt"
    "io/ioutil"
    "path/filepath"

    "gopkg.in/yaml.v2"
)

type Config struct {
    Firewall_network_rules map[string][]string
}

func main() {
    filename, _ := filepath.Abs("./fruits.yml")
    yamlFile, err := ioutil.ReadFile(filename)

    if err != nil {
        panic(err)
    }

    var config Config

    err = yaml.Unmarshal(yamlFile, &config)
    if err != nil {
        panic(err)
    }

    fmt.Printf("Value: %#v\n", config.Firewall_network_rules)
}

当我运行它时,我得到一个错误。我认为这是因为我还没有为 src 和 dst 键/值创建结构。仅供参考:当我将其更改为列表时,它可以工作。

所以上面的代码解析了这个:

---
firewall_network_rules:
  rule1:
    - value1
    - value2
...

【问题讨论】:

    标签: struct go yaml


    【解决方案1】:

    如果您更具体地使用 google cloud 或 kubernetes,并希望像这样解析 service.yaml:

    apiVersion: v1
    kind: Service
    metadata:
      name: myName
      namespace: default
      labels:
        router.deis.io/routable: "true"
      annotations:
        router.deis.io/domains: ""
    spec:
      type: NodePort
      selector:
        app: myName
      ports:
        - name: http
          port: 80
          targetPort: 80
        - name: https
          port: 443
          targetPort: 443
    

    提供一个真实世界的示例,以便您了解如何编写嵌套。

    type Service struct {
        APIVersion string `yaml:"apiVersion"`
        Kind       string `yaml:"kind"`
        Metadata   struct {
            Name      string `yaml:"name"`
            Namespace string `yaml:"namespace"`
            Labels    struct {
                RouterDeisIoRoutable string `yaml:"router.deis.io/routable"`
            } `yaml:"labels"`
            Annotations struct {
                RouterDeisIoDomains string `yaml:"router.deis.io/domains"`
            } `yaml:"annotations"`
        } `yaml:"metadata"`
        Spec struct {
            Type     string `yaml:"type"`
            Selector struct {
                App string `yaml:"app"`
            } `yaml:"selector"`
            Ports []struct {
                Name       string `yaml:"name"`
                Port       int    `yaml:"port"`
                TargetPort int    `yaml:"targetPort"`
                NodePort   int    `yaml:"nodePort,omitempty"`
            } `yaml:"ports"`
        } `yaml:"spec"`
    }
    

    有一个名为 yaml-to-go https://yaml.to-go.online/ 的便捷服务将 YAML 转换为 go 结构,只需将您的 YAML 输入到该服务中,您就会得到一个自动生成的结构。

    最后解组,正如之前的海报所写:

    var service Service
    
    err = yaml.Unmarshal(yourFile, &service)
    if err != nil {
        panic(err)
    }
    
    fmt.Print(service.Metadata.Name)
    

    【讨论】:

      【解决方案2】:

      如果您不关心规则名称,为什么不按如下方式组织您的 yaml 文件?

      ---
      firewall_network_rules:
        - 
          name:      rule1
          src:       blablabla-host
          dst:       blabla-hostname
        - 
          name:      rule2
          src:       bla-host
          dst:       bla-hostname
      

      所以代码会是这样,干净且可扩展:

      type Rule struct {
          Name  string  `yaml:"name"`
          Src   string  `yaml:"src"`
          Dst   string  `yaml:"dst"`
      }
      
      type Config struct {
         FirewallNetworkRules []Rule  `yaml:"firewall_network_rules"`
      }
      

      【讨论】:

        【解决方案3】:

        嗯,我想我已经自己想通了。以下代码可以正常工作。有什么建议/改进吗?

        package main
        
        import (
            "fmt"
            "io/ioutil"
            "path/filepath"
        
            "gopkg.in/yaml.v2"
        )
        
        type Config struct {
            Firewall_network_rules map[string]Options
        }
        
        type Options struct {
            Src string
            Dst string
        }
        
        func main() {
            filename, _ := filepath.Abs("./fruits.yml")
            yamlFile, err := ioutil.ReadFile(filename)
        
            if err != nil {
                panic(err)
            }
        
            var config Config
        
            err = yaml.Unmarshal(yamlFile, &config)
            if err != nil {
                panic(err)
            }
        
            fmt.Printf("Value: %#v\n", config.Firewall_network_rules)
        }
        

        【讨论】:

        • 尝试更惯用的 FirewallNetworkRules 并添加一个结构标记来捕获 YAML 格式 - 例如` yaml:"firewall_network_rules" ` 有关 YAML 库中结构标记用法的文档,请参见此处:godoc.org/gopkg.in/yaml.v2#Marshal
        • 感谢您的建议,它确实澄清了我的代码。
        【解决方案4】:

        如果您的 YAML 文件很简单(单嵌套),如下所示

        mongo:
            DB: database
            COL: collection
        log:
            error: log/error/error.log
        api:
            key: jhgwewbcjwefwjfg
        

        在这里,你可以使用接口而不是声明结构。

        main(){
          config := Config()
          mongoConfig := config["mongo"]
        
          mongo.MongoDial(
            String(
                Get(mongoConfig, "DB")
            ), 
            String(
                Get(mongoConfig, "COL")
            )
          )
        }
        
        func Config() map[string]interface{} {
            filename, _ := filepath.Abs("configs/config.yaml")
            yamlFile, err := ioutil.ReadFile(filename)
        
            if err != nil {
                panic(err)
            }
        
            var config map[string]interface{}
        
            err = yaml.Unmarshal(yamlFile, &config)
            if err != nil {
                panic(err)
            }
        
            return config
        }
        func Get(this interface{}, key string) interface{}  {
            return this.(map[interface{}]interface{})[key]
        }
        func String(payload interface{}) string  {
            var load string
            if pay, oh := payload.(string); oh {
                load = pay
            }else{
                load = ""
            }
            return load
        }
        

        这适用于 1 级嵌套,如果您有复杂的嵌套,建议使用struct

        【讨论】:

          猜你喜欢
          • 2014-11-05
          • 1970-01-01
          • 2020-10-14
          • 2020-07-18
          • 1970-01-01
          • 2018-08-04
          相关资源
          最近更新 更多