Home > Blockchain >  Preserving order in YAML file in Go
Preserving order in YAML file in Go

Time:07-29

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

CodePudding user response:

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.

  • Related