在没有结构的情况下将 yaml 转换为 json

Posted

技术标签:

【中文标题】在没有结构的情况下将 yaml 转换为 json【英文标题】:Convert yaml to json without struct 【发布时间】:2017-04-05 20:22:10 【问题描述】:
Services: 
-   Orders: 
    -   ID: $save ID1
        SupplierOrderCode: $SupplierOrderCode
    -   ID: $save ID2
        SupplierOrderCode: 111111

我想把这个yaml字符串转换成json,因为源数据是动态的,所以我不能把它映射到结构体:

var body interface
err := yaml.Unmarshal([]byte(s), &body)

那我想再把那个接口转成json字符串:

b, _ := json.Marshal(body)

但是发生错误:

panic: json: unsupported type: map[interface ]interface 

【问题讨论】:

像这样创建正文变量:body := make(map[string]interface) 【参考方案1】:

前言:我对以下解决方案进行了优化和改进,并在此处将其作为库发布:github.com/icza/dyno。以下convert() 函数可作为dyno.ConvertMapI2MapS() 使用。


问题在于,如果您使用最通用的interface 类型来解组,则github.com/go-yaml/yaml 包用于解组键值对的默认类型将是map[interface]interface

第一个想法是使用map[string]interface

var body map[string]interface

但如果 yaml 配置的深度大于 1,则此尝试会失败,因为此 body 映射将包含其他类型将再次为 map[interface]interface 的映射。

问题是深度未知,可能还有地图以外的其他值,所以使用map[string]map[string]interface不好。

一种可行的方法是让yaml 解组为interface 类型的值,并递归地处理结果,并将遇到的每个map[interface]interface 转换为map[string]interface 值。地图和切片都必须处理。

下面是这个转换器函数的一个例子:

func convert(i interface) interface 
    switch x := i.(type) 
    case map[interface]interface:
        m2 := map[string]interface
        for k, v := range x 
            m2[k.(string)] = convert(v)
        
        return m2
    case []interface:
        for i, v := range x 
            x[i] = convert(v)
        
    
    return i

并使用它:

func main() 
    fmt.Printf("Input: %s\n", s)
    var body interface
    if err := yaml.Unmarshal([]byte(s), &body); err != nil 
        panic(err)
    

    body = convert(body)

    if b, err := json.Marshal(body); err != nil 
        panic(err)
     else 
        fmt.Printf("Output: %s\n", b)
    


const s = `Services:
-   Orders:
    -   ID: $save ID1
        SupplierOrderCode: $SupplierOrderCode
    -   ID: $save ID2
        SupplierOrderCode: 111111
`

输出:

Input: Services:
-   Orders:
    -   ID: $save ID1
        SupplierOrderCode: $SupplierOrderCode
    -   ID: $save ID2
        SupplierOrderCode: 111111

Output: "Services":["Orders":[
    "ID":"$save ID1","SupplierOrderCode":"$SupplierOrderCode",
    "ID":"$save ID2","SupplierOrderCode":111111]]

需要注意的一点:通过 Go 映射从 yaml 切换到 JSON,您将失去项目的顺序,因为 Go 映射中的元素(键值对)没有排序。这可能是也可能不是问题。

【讨论】:

非常感谢 Icza,你真好 :D【参考方案2】:

http://sigs.k8s.io/yaml 是“一个围绕 go-yaml 的包装器,旨在在编组到结构体和从结构体传出时提供更好的 YAML 处理方式”。除此之外,它还提供了yaml.YAMLToJSON 方法,可以满足您的需求。

【讨论】:

以上是关于在没有结构的情况下将 yaml 转换为 json的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有可选值的情况下将字典数组快速转换为json字符串[重复]

如何在没有副本的情况下将结构转换为字节数组?

如何在不将 LocalDateTime 字段转换为扩展的 json 对象的情况下将 java 对象转换为简单的 json 字符串?

如何在不使用 C# 中的 T 对象的情况下将 Json 数组转换为单个 JSON 对象?

如何在不转换为json的情况下将C#数组用于javascript数组?

Postgresql:如何在不使用中间 hstore 的情况下将键值表转换为 json