Skip to content

Instantly share code, notes, and snippets.

@thrawn01
Last active June 8, 2023 02:13
Show Gist options
  • Save thrawn01/de8b4c086a0626e73df7a455c05032a9 to your computer and use it in GitHub Desktop.
Save thrawn01/de8b4c086a0626e73df7a455c05032a9 to your computer and use it in GitHub Desktop.
A bit of code to convert a struct into yaml.Node structure.
import "gopkg.in/yaml.v3"
func StructToYAMLNode(data interface{}, node *yaml.Node) error {
value := reflect.ValueOf(data)
switch value.Kind() {
case reflect.Struct:
// If the struct has a `String()` method call that instead
if strMethod := value.MethodByName("String"); strMethod.IsValid() {
obj := strMethod.Call(nil)[0].Interface()
node.Kind = yaml.ScalarNode
node.Tag = "!!str"
node.Value = obj.(string)
return nil
}
node.Kind = yaml.MappingNode
node.Tag = "!!map"
for i := 0; i < value.NumField(); i++ {
field := value.Type().Field(i)
fieldValue := value.Field(i)
fieldName := field.Name
// Skip unexported fields
if field.PkgPath != "" {
continue
}
// Only include fields with a non zero value
if setter.IsZero(value) {
continue
}
if field.Tag.Get("json") == "-" {
continue
}
fieldNode := &yaml.Node{Kind: yaml.ScalarNode, Tag: "!!str", Value: fieldName}
valueNode := &yaml.Node{}
if err := StructToYAMLNode(fieldValue.Interface(), valueNode); err != nil {
return err
}
node.Content = append(node.Content, fieldNode, valueNode)
}
case reflect.String:
node.Kind = yaml.ScalarNode
node.Tag = "!!str"
node.Value = value.String()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
node.Kind = yaml.ScalarNode
node.Tag = "!!int"
node.Value = fmt.Sprintf("%d", value.Int())
case reflect.Float32, reflect.Float64:
node.Kind = yaml.ScalarNode
node.Tag = "!!float"
node.Value = fmt.Sprintf("%f", value.Float())
case reflect.Slice:
node.Kind = yaml.SequenceNode
node.Tag = "!!seq"
for i := 0; i < value.Len(); i++ {
elemNode := &yaml.Node{}
if err := StructToYAMLNode(value.Index(i).Interface(), elemNode); err != nil {
return err
}
node.Content = append(node.Content, elemNode)
}
case reflect.Map:
node.Kind = yaml.MappingNode
node.Tag = "!!map"
mapKeys := value.MapKeys()
for _, key := range mapKeys {
keyNode := &yaml.Node{}
if err := StructToYAMLNode(key.Interface(), keyNode); err != nil {
return err
}
valueNode := &yaml.Node{}
if err := StructToYAMLNode(value.MapIndex(key).Interface(), valueNode); err != nil {
return err
}
node.Content = append(node.Content, keyNode, valueNode)
}
case reflect.Bool:
node.Kind = yaml.ScalarNode
node.Tag = "!!bool"
node.Value = fmt.Sprintf("%t", value.Bool())
case reflect.Ptr:
if value.IsNil() {
node.Kind = yaml.ScalarNode
node.Tag = "!!null"
node.Value = "null"
} else {
return StructToYAMLNode(value.Elem().Interface(), node)
}
default:
return fmt.Errorf("unsupported type: %v", value.Kind())
}
return nil
}
func main() {
data := LimitItem{
Id: "10979324056a",
Limit: 20000,
Count: 1500,
}
root := &yaml.Node{Kind: yaml.DocumentNode}
err := openapi.StructToYAMLNode(data, root)
require.NoError(t, err)
spew.Dump(root)
b, err := yaml.Marshal(root)
require.NoError(t, err)
fmt.Printf("---\n%s\n---\n", string(b))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment