卓越飞翔博客卓越飞翔博客

卓越飞翔 - 您值得收藏的技术分享站
技术文章34589本站已运行393

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

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

php小编草莓介绍:YAML是一种轻量级的数据序列化格式,它具有简洁易读的语法,被广泛用于配置文件和数据交换。在PHP中,我们可以使用YAML解析库将YAML数据解组为复杂对象,这些对象可以是结构体或字符串。这为开发人员提供了一种方便的方式来处理和操作配置文件和其他数据。无论是构建复杂的应用程序还是简化配置管理,YAML解析在PHP中发挥着重要的作用。

问题内容

尝试将 yaml 解组为复杂对象,例如 map[string]map[interface{}]string。 问题是我希望能够区分 stringsource 之间的 interface{} 部分,这是一个结构。

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"`
}

显然 yaml 不知道如何解组到 source 结构中,所以我必须实现 unmarshaler 接口:

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

但我不太了解解组过程的总体情况。一般来说,我假设我必须手动遍历 *yaml.node 并在每个节点上调用 func unmarshalyaml(value *node) error

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
}

去游乐场

解决方法

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

如果您需要保持映射类型不变,即不添加自定义键类型,那么您也可以在 unft 上实现解组器,只需使用 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

卓越飞翔博客
上一篇: 如何在 fyne-io/fyne 中设置文本的字母间距?
下一篇: 返回列表
留言与评论(共有 0 条评论)
   
验证码:
隐藏边栏