去解析yaml文件

Posted

技术标签:

【中文标题】去解析yaml文件【英文标题】:Go parse yaml file 【发布时间】: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
...

【问题讨论】:

【参考方案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

【讨论】:

以上是关于去解析yaml文件的主要内容,如果未能解决你的问题,请参考以下文章

yaml文件解析

yaml文件解析

yaml文件解析

yaml文件解析

解析 YAML 文件?

在 Python 中解析 YAML 文件并访问数据?