-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Parsing array of string or single string #100
Comments
I have the same problem. Did you find a solution meanwhile? |
I managed to get something working using the Unmarshall interface package main
import (
"fmt"
"gopkg.in/yaml.v2"
)
const (
data = `
attrs:
foo: bar
bar:
- 1
- 2
- 3
`
)
type SingleOrMulti struct {
Values []string
}
func (sm *SingleOrMulti) UnmarshalYAML(unmarshal func(interface{}) error) error {
var multi []string
err := unmarshal(&multi)
if err != nil {
var single string
err := unmarshal(&single)
if err != nil {
return err
}
sm.Values = make([]string, 1)
sm.Values[0] = single
} else {
sm.Values = multi
}
return nil
}
type Data struct {
Attrs map[string]SingleOrMulti
}
func main() {
var t Data
yaml.Unmarshal([]byte(data), &t)
fmt.Printf("%d\n", len(t.Attrs))
for k, e := range t.Attrs {
fmt.Printf("%v: %v\n", k, e.Values)
}
} Using this I always have a slice in the unmarshaled struct, which gets a single element in case the YAML was a single value. Note that in this example, attrs: had arbitrary key names so I used a map. You can as well use a struct, if the names are fixed: type Data struct {
Foo SingleOrMulti
Bar SingleOrMulti
} |
@dmacvicar I had left this as a todo for later on so thank you very much for finding a solution. You have just taught me how to use this library even more effectively. I did not realize there was an Unmarshaler type! I can now parse some other more complex values right from the beginning. Very awesome. |
You closed the issue, but I still think this is an issue. It would be great if one could do something like: type Data struct {
Field []string `yaml:"alwaysarray"`
} And no matter if someone writes: field: foobar That would put the value as the only element of the array. |
@dmacvicar A slightly modified version of the code above gives you something similar to what you're asking for. type StringArray []string
func (a *StringArray) UnmarshalYAML(unmarshal func(interface{}) error) error {
var multi []string
err := unmarshal(&multi)
if err != nil {
var single string
err := unmarshal(&single)
if err != nil {
return err
}
*a = []string{single}
} else {
*a = multi
}
return nil
}
type Data struct {
Field StringArray
} Now you can access |
What's the status? It would be awesome to land this feature. |
Any update on this? It should be very good to have this feature. |
+1 |
Building off of dolfelt's code, here's how you could workaround this if you're using v3 of this package: type StringArray []string
func (a *StringArray) UnmarshalYAML(value *yaml.Node) error {
var multi []string
err := value.Decode(&multi)
if err != nil {
var single string
err := value.Decode(&single)
if err != nil {
return err
}
*a = []string{single}
} else {
*a = multi
}
return nil
}
type Data struct {
Field StringArray
} |
I ran into this issue recently and have added a patch in a fork here. I'll work to get a full patch submitted as a PR on this repo. |
PR added #974. Please let me know if there's anything missing and/or necessary. Happy to update where necessary. |
Can we move that ticket to some FAQ ? |
I need to parse some files and some fields can either include an array of strings or can just include 1 element that's inlined. How do I parse such a file?
or
I tried
field []string
but that of course only works for the bottom example andfield string
only works for the top one. I thought maybefield []string ",inline"
but that's limited to structs. Any idea on how to achieve it? One, could think of the inlined string as an array of 1 length...The text was updated successfully, but these errors were encountered: