Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Go unmarshal yaml and preserve order

Let's say I have the following yaml file:

key1:
    - "Value1"
    - "Value2"
key2:
    - "Value3"
    - "Value4"

And I want to unmarshal that in Go. I can let Go decide what the scheme should look like and print it out.

m := make(map[interface{}]interface{})
err := yaml.Unmarshal(yaml_file, &m)
fmt.Prinf(m)

This will print something like this: map[key1:[Value1 Value2] key2:[Value3 Value4]]

But maps are unordered. The order is very important for me tho and I also don't want to loose the keys.

I can't just create a struct and try to unmarshal the yaml file to a slice of that struct...

type Element struct {
    Key   string
    Value interface{}
}

t := []Element{}
err := yaml.Unmarshal(yaml_file, &t)
if err != nil {
    log.Fatalf("error: %v", err)
}

Will print error: yaml: unmarshal errors: line 2: cannot unmarshal !!map into []Element

There is no field tag to tell the yaml parser to fill the Key property with the yaml key.

Is there a different way than writing my own decoder?

like image 316
noranraskin Avatar asked Oct 18 '25 02:10

noranraskin


1 Answers

Just found the answer right before I wanted to post the question.

The answer is MapSlice! You need to import yaml.v2 from gopkg. (As of writing this MapSlices don't seem to be implemented in yaml.v3 yet)

MapSlices implement exactly what I needed and are made of a number of MapItems.

type MapItem struct {
    Key, Value interface{}
}

So now just unmarshal to a MapSlice. If you want to work with your own types you can always convert it but might need to do some typecasting.

m := yaml.MapSlice{}
yaml.Unmarshal(yaml_file, &m)

t := []Element{}
for _, item := range m {
    t = append(t, Element{item.Key.(string), item.Value})
}
like image 115
noranraskin Avatar answered Oct 20 '25 21:10

noranraskin