在Go语言中保留YAML文件的顺序

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

Preserving order in YAML file in Go

问题

我正在尝试读取一个 YAML 文件中的数据,它的格式如下:

Category Name:
  Task 1:
    Name: Meeting
    PM: 1
    TC: 0
    STC: 1
    Optional: false

一个类别中可以有多个任务,而且可以有多个类别。我最初是这样读取 YAML 文件的。

type Task struct {
	Name     string
	PM       string
	TC       string
	STC      string
	Optional bool
}
type Category struct {
	Name  string
	Tasks []Task
}
func parseFile() map[string]map[string]map[string]string {
	file, err := ioutil.ReadFile("config.yaml")

	if err != nil {
		log.Fatal(err)
	}

	data := make(map[string]map[string]map[string]string)
	err1 := yaml.Unmarshal(file, &data)

	if err1 != nil {
		log.Fatal(err1)
	}

	return data
}

然后,我只需在 parseFile() 创建的映射中循环,并使用填充的信息创建一个 Category 列表。这个方法很好用... 除了一个问题,由于映射不是有序的,所以无法保留 YAML 文件中类别/任务的顺序。

从网上的资料中,我发现可以使用 gokpg.in/yaml.v2 中的 yaml.MapSlice{} 来保留顺序。然而,我不知道如何处理得到的 MapSlice。我可以遍历它以获取类别,但无法遍历 .Value,因为 MapItems 是接口类型,而 MapItems 将存储我的任务列表。我应该怎么做才能获取任务并放入 []Task 中呢?

谢谢帮助 在Go语言中保留YAML文件的顺序

英文:

I am trying to read data in a YAML file which looks like this:

Category Name:
  Task 1:
    Name: Meeting
    PM: 1
    TC: 0
    STC: 1
    Optional: false

There can be multiple tasks in a category and multiple categories. I've originally been reading the YAML file like so.

type Task struct {
	Name     string
	PM       string
	TC       string
	STC      string
	Optional bool
}
type Category struct {
	Name  string
	Tasks []Task
}
func parseFile() map[string]map[string]map[string]string {
	file, err := ioutil.ReadFile("config.yaml")

	if err != nil {
		log.Fatal(err)
	}

	data := make(map[string]map[string]map[string]string)
	err1 := yaml.Unmarshal(file, &data)

	if err1 != nil {
		log.Fatal(err1)
	}

	return data
}

Then I just have a function to loop through the map created in parseFile() and create a list of Category with the filled in information. This works great... other than the fact that the order of categories/tasks written in the YAML file is not preserved because of maps not being ordered.

From reading online, I found that you can preserve the order using yaml.MapSlice{} from gokpg.in/yaml.v2. However, I have no idea what to do with this resulting MapSlice. I can iterate through it to get the categories but I can't iterate through the .Value since MapItems are interfaces, but MapItems would store my list of tasks. What can I do so I can do so I can get the tasks and put in a []Task?

Help is appreciated 在Go语言中保留YAML文件的顺序

答案1

得分: 0

我通过更改我的YAML和结构的格式,然后直接解组到结构中来解决了这个问题。

新的结构体如下:

type Categories struct {
	Category []struct {
		Name string `yaml:"CategoryName"`
		Task []struct {
			Name     string  `yaml:"TaskName"`
			PM       float64 `yaml:"PM"`
			TC       float64 `yaml:"TC"`
			STC      float64 `yaml:"STC"`
			Optional bool    `yaml:"Optional"`
		} `yaml:"Tasks"`
	} `yaml:"Categories"`
}

YAML文件的新格式以支持结构体中的内容如下:

Categories:
  - CategoryName: Category 1
    Tasks:
      - TaskName: Test 1
        PM: 1
        TC: 0
        STC: 1
        Optional: false
      - TaskName: Test 2
        PM: 2
        TC: 0
        STC: 2
        Optional: false
  - CategoryName: Category 2
    Tasks:
      - TaskName: Test 3
        PM: 1
        TC: 2
        STC: 3
        Optional: true

将YAML文件直接解组到新的结构体中:

var tasks Categories
file, err := ioutil.ReadFile("config.yaml")

if err != nil {
	log.Fatal(err)
}

yaml.Unmarshal(file, &tasks)

这样做可以解决我的问题——不再使用映射,因此顺序得到保留,并且以我认为易于循环遍历的方式使用结构体。

英文:

I managed to solve this by changing the format of my YAML and structures, then unmarshalling directly into the structure.

The new structs.

type Categories struct {
	Category []struct {
		Name string `yaml:"CategoryName"`
		Task []struct {
			Name     string  `yaml:"TaskName"`
			PM       float64 `yaml:"PM"`
			TC       float64 `yaml:"TC"`
			STC      float64 `yaml:"STC"`
			Optional bool    `yaml:"Optional"`
		} `yaml:"Tasks"`
	} `yaml:"Categories"`
}

The new format for the YAML file to support what's in the struct.

Categories:
  - CategoryName: Category 1
    Tasks:
      - TaskName: Test 1
        PM: 1
        TC: 0
        STC: 1
        Optional: false
      - TaskName: Test 2
        PM: 2
        TC: 0
        STC: 2
        Optional: false
  - CategoryName: Category 2
    Tasks:
      - TaskName: Test 3
        PM: 1
        TC: 2
        STC: 3
        Optional: true

Unmarshalling the YAML file directly into a new struct

var tasks Categories
	file, err := ioutil.ReadFile("config.yaml")

	if err != nil {
		log.Fatal(err)
	}

	yaml.Unmarshal(file, &tasks)

This worked to fix my problem - no longer using maps so the order is preserved and using the structs in a way that I find easy to loop through.

答案2

得分: 0

package main

import (
	"fmt"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"log"
)

type Config struct {
	CategoryName []map[string]Task `yaml:"CategoryName"`
}

type Task struct {
	Name     string `yaml:"Name"`
	PM       int    `yaml:"PM"`
	TC       int    `yaml:"TC"`
	STC      int    `yaml:"STC"`
	Optional bool   `yaml:"Optional"`
}

func main() {
	yamlData := []byte(`
CategoryName:
  - Task1:
      Name: "Meeting"
      PM: 1
      TC: 0
      STC: 1
      Optional: false
  - Task2:
      Name: "Meeting v2"
      PM: 2
      TC: 0
      STC: 2
      Optional: false
`)

	var config Config
	err := yaml.Unmarshal(yamlData, &config)
	if err != nil {
		log.Fatalf("Erreur lors de la décomposition du YAML : %v", err)
	}

	fmt.Printf("Configuration : %+v\n", config)
}

以上是要翻译的代码部分。

英文:
package main

import (
	"fmt"
	"gopkg.in/yaml.v2"
	"io/ioutil"
	"log"
)

type Config struct {
	CategoryName []map[string]Task `yaml:"CategoryName"`
}

type Task struct {
    Name string `yaml:"Name"`
    PM int `yaml:"PM"`
    TC int `yaml:"TC"`
    STC int `yaml:"STC"`
    Optional bool  `yaml:"Optional"`
}

func main() {
	yamlData := []byte(`
CategoryName:
  - Task1:
      Name: "Meeting"
      PM: 1
      TC: 0
      STC: 1
      Optional: false
  - Task2:
      Name: "Meeting v2"
      PM: 2
      TC: 0
      STC: 2
      Optional: false
`)

	var config Config
	err := yaml.Unmarshal(yamlData, &config)
	if err != nil {
		log.Fatalf("Erreur lors de la décomposition du YAML : %v", err)
	}

	fmt.Printf("Configuration : %+v\n", config)
}

huangapple
  • 本文由 发表于 2022年7月26日 20:51:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/73123698.html
匿名

发表评论

匿名网友

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

确定