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.
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"` }
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 }
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 }
Go to the amusement park
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"` }
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 }
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!