解析 YAML 文件

huangapple go评论91阅读模式
英文:

Go parse yaml file

问题

我正在尝试使用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)
}

当我运行这段代码时,我得到一个错误。我认为这是因为我没有为srcdst键/值创建一个结构体。当我将它们改为列表时,代码可以正常工作。

所以上述代码解析以下内容:

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

希望对你有帮助!

英文:

I'm trying to parse a yaml file with Go. Unfortunately I can't figure out how. The yaml file I have is this:

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

I have this Go code, but it does not work:

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

When I run this, I get an error. I think it's because I haven't created a struct for the src and dst key/values. FYI: when I change that to a list, it works.

So above code parses this:

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

答案1

得分: 47

如果你正在使用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://zhwt.github.io/yaml-to-go/),它可以将YAML转换为Go结构体,只需将你的YAML输入到该服务中,就会得到一个自动生成的结构体。

同样,也有一个JSON的等效工具:https://mholt.github.io/json-to-go/

最后,像之前的帖子所写的那样进行解组:

var service Service

err = yaml.Unmarshal(yourFile, &service)
if err != nil {
    panic(err)
}

fmt.Print(service.Metadata.Name)
英文:

If you're working with google cloud or kubernetes more specifically and want to parse a service.yaml like this:

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

Supplying a real world example so you get the hang of how nesting can be written.

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"`
}

There's a convenient service called yaml-to-go https://zhwt.github.io/yaml-to-go/ which converts YAML to go structs, just input your YAML into that service and you get an autogenerated struct.

A JSON equivalent exists aswell: https://mholt.github.io/json-to-go/

And last unmarshal as a previous poster wrote:

var service Service

err = yaml.Unmarshal(yourFile, &service)
if err != nil {
    panic(err)
}

fmt.Print(service.Metadata.Name)

答案2

得分: 11

好的,以下是翻译好的代码:

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

希望对你有帮助!如果有其他问题,请随时提问。

英文:

Well, I think I've figured it out by myself. The following piece of code works fine. Any suggestions/improvements?

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

答案3

得分: 10

如果你不关心规则名称,为什么不按照下面的方式组织你的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"`
}
英文:

Why not organize your yaml file like below if you don't care about the rule name?

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

So the code will be like this, it is clean and extensible:

type Rule struct {
    Name  string  `yaml:"name"`
    Src   string  `yaml:"src"`
    Dst   string  `yaml:"dst"`
}

type Config struct {
   FirewallNetworkRules []Rule  `yaml:"firewall_network_rules"`
}

答案4

得分: 2

如果您的YAML文件是简单的(单层嵌套)如下所示:

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

在这种情况下,您可以使用接口(interface)而不是声明结构体(struct)。

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
}

这对于一级嵌套的情况下可以正常工作,如果您有复杂的嵌套,则建议使用struct

英文:

If your YAML file is simple (single nesting) like following

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

Here, you can use interface instead of declaring struct.

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
}

This works fine for level 1 nesting, if you have complex nesting then it is recommended to use struct.

huangapple
  • 本文由 发表于 2015年2月24日 04:05:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/28682439.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定