Home > Backend Development > Golang > Unmarshal YAML into complex objects, either structs or strings

Unmarshal YAML into complex objects, either structs or strings

WBOY
Release: 2024-02-09 08:48:29
forward
941 people have browsed it

将 YAML 解组为复杂对象,可以是结构体或字符串

php editor strawberry introduction: YAML is a lightweight data serialization format. It has a concise and easy-to-read syntax and is widely used for configuration files and data exchange. In PHP, we can use the YAML parsing library to unmarshal YAML data into complex objects, which can be structures or strings. This provides developers with a convenient way to handle and manipulate configuration files and other data. Whether building complex applications or simplifying configuration management, YAML parsing plays an important role in PHP.

Question content

Try to unmarshal yaml into complex objects, such as map[string]map[interface{}]string. The problem is that I want to be able to differentiate between the string and the source part of the interface{}, which is a struct.

type source struct {
    id     string `yaml:"id"`
    name   string `yaml:"name"`
    logoid string `yaml:"logoid"`
    url    string `yaml:"url"`
}

type unft struct {
    itemmeta map[string]map[interface{}]string `yaml:"item_meta"`
    // could be
    // itemmeta map[string]map[string]string `yaml:"item_meta"`
    // or
    // itemmeta map[string]map[source]string `yaml:"item_meta"`
}
Copy after login

Apparently yaml doesn't know how to unmarshal into a source structure, so I have to implement the unmarshaler interface:

type unmarshaler interface {
    unmarshalyaml(value *node) error
}
Copy after login

But I don't quite understand the overall situation of the unmarshalling process. Generally speaking, I assume I have to manually iterate through *yaml.node and call func unmarshalyaml(value *node) error on each node.

package main

import (
    "fmt"

    "gopkg.in/yaml.v3"
)

type Source struct {
    ID     string `json:"id"`
    Name   string `json:"name"`
    LogoID string `json:"logoId"`
    URL    string `json:"url"`
}

var data = `
unf:
    item_meta:
      source:
           !struct
           ? id: "data-watch" 
             name: "DataWatch"
             logoid: "data-watch"
             url: "https"
           : "product_any('SS')"
      public_usage:
        "": "source_any('SDF')"
        "provider": "source_any('ANO')"`

type UNFT struct {
    ItemMeta map[string]map[interface{}]string `yaml:"item_meta"`
}

type MetaConverterConfigT struct {
    UNFT UNFT `yaml:"unf"`
}

func main() {
    cfg := MetaConverterConfigT{}

    err := yaml.Unmarshal([]byte(data), &cfg)
    if err != nil {
        fmt.Println("%w", err)
    }

    fmt.Println(cfg)
}

func (s *UNFT) UnmarshalYAML(n *yaml.Node) error {
    var cfg map[string]map[interface{}]string
    if err := n.Decode(&cfg); err != nil {
        fmt.Println("%w", err)
    }

    return nil
}
Copy after login

Go to the amusement park

Solution

type metakey struct {
    string string
    source source
}

func (k *metakey) unmarshalyaml(n *yaml.node) error {
    if n.tag == "!!str" {
        return n.decode(&k.string)
    }
    if n.tag == "!!map" {
        return n.decode(&k.source)
    }
    return fmt.errorf("unsupported metakey type")
}

// ...

type unft struct {
    itemmeta map[string]map[metakey]string `yaml:"item_meta"`
}
Copy after login

https://www.php.cn/link/50f9999b2ee27e222c5513e945e9ea9c

If you need to keep the mapping type unchanged, i.e. without adding a custom key type, then you can also implement the unmarshaller on unft and just remap using any:

type UNFT struct {
    ItemMeta map[string]map[any]string `yaml:"item_meta"`
}

func (u *UNFT) UnmarshalYAML(n *yaml.Node) error {
    var obj struct {
        ItemMeta map[string]map[MetaKey]string `yaml:"item_meta"`
    }
    if err := n.Decode(&obj); err != nil {
        return err
    }

    u.ItemMeta = make(map[string]map[any]string, len(obj.ItemMeta))
    for k, v := range obj.ItemMeta {
        m := make(map[any]string, len(v))
        for k, v := range v {
            if k.Source != (Source{}) {
                m[k.Source] = v
            } else {
                m[k.String] = v
            }
        }
        u.ItemMeta[k] = m
    }
    return nil
}
Copy after login

https://www.php.cn/link/543378fb36a83810ded2d725f2b6c883

The above is the detailed content of Unmarshal YAML into complex objects, either structs or strings. For more information, please follow other related articles on the PHP Chinese website!

source:stackoverflow.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template