XY problem: I'm trying to read in a YAML file such as the one below, and output a set of tuples that combine certain keys and values from the YAML file. E.g. given this YAML data:
---
fruit:
apple:
colour:
- green
'banana':
colour:
- yellow
pear:
colour:
- green
- yellow
I want to combine each key under "fruit" with each value under "colour" into tuples. My tuples would look like this:
apple:green
banana:yellow
pear:green
pear:yellow
To do this, I'm using a map[string]interface{} to Unmarshal my YAML data into Go - I can't use a struct because the names of the keys below "fruit" could be anything, so I need to use a dynamic type. This is my code so far:
package main
import (
"fmt"
"log"
"gopkg.in/yaml.v3"
)
var data string = `
---
fruit:
apple:
colour:
- green
'banana':
colour:
- yellow
pear:
colour:
- green
- yellow
`
func main() {
m := make(map[string]interface{})
err := yaml.Unmarshal([]byte(data), &m)
if err != nil {
log.Fatal("Failed to parse YAML file")
}
for _, v := range m {
fruits := v.(map[string]interface{})
for fruit, v2 := range fruits {
colours := v2.(map[string]interface{})["colour"]
for colour := range colours {
fmt.Println("%v:%v\n", fruit, colour)
}
}
}
}
Playground link: https://go.dev/play/p/v8iuzmMLtjX
The problem is for colour := range colours
- I get the error:
cannot range over colours (type interface {})
I found this answer to a similar question which says that I cannot directly convert a []interface{} to []string, and must instead iterate over the values. That's what I've tried to do here. The v2
variable works out to a map[string]interface {}
type, which for example could be map[colour:[green yellow]]
. Then I've tried converting that into another map[string]interface{} to get the value of "colour", which works out to a []interface{} type [green yellow]
and is stored in the colours
variable.
But I can't iterate over colours
for some reason. I don't understand what's different about my solution and icza's solution in the linked answer (I've linked their Playground link). The data type of colours
in my solution is []interface{}, and in icza's solution the data type of t
is also []interface{} - but in that case it is possible to iterate through the slice and access the values within.
Another solution I tried was from this answer to a different question, which was to try directly converting the []interface{} to a []string:
c := colours.([]string)
That also didn't work:
panic: interface conversion: interface {} is []interface {}, not []string
What do I need to do to make this solution work?