繁体   English   中英

将复杂结构转换为简单 json

[英]Converting a complex struct to a simple json

背景

我有一个结构,我通过 API 作为 json 传递给用户。 这行得通。

我现在正在尝试发送与 object 相同的结构,我的 UI 可以轻松转换为 csv 并允许用户下载。

我有在 UI 上工作的代码,可以将简单对象转换为 CSV。 所以我可以发送一个 object 值只是整数或字符串没问题。 但是,我的结构的值是对象和 arrays。 因此,我正在尝试找到一种方法将复杂的 json object 转换为更简单的方法。 更简单的 object 应该只具有没有引号的值(如 int)或只有一组外部引号(如字符串)。

问题

如何将 golang 结构转换为具有“简单”值(字符串、布尔值、int 但不是数组或带有更多引号的 object)的 json?

例子

例如,此代码将用户转换为 json,格式如下:

{
 "Name":"Frank",
 "Friends":[{"Age":10,"Name":"Joe"}, {"Age":12,"Name":"John"}],
 "FavSnacks":["apple","orange"]
}

,但我想要格式

 {
  "Name":"Frank",
  "Friends":"[{'Age':10,'Name':'Joe'},{'Age':12,'Name':'John'}]",
  "FavSnacks":"['apple','orange']"
 }

或者

 {
  "Name":"Frank",
  "Friends":"[{Age:10, Name:Joe},{Age:12,Name:John}]",
  "FavSnacks":"[apple, orange]"
 }

这是我的代码

package main

import (
    "fmt"
    "encoding/json"
)

type User struct {
    Name string
    Friends []Friend
    FavSnacks []string
}

type Friend struct {
    Age int
    Name string
}

func main() {
    user := &User{Name: "Frank", FavSnacks: []string{"apple","orange"}, Friends: []Friend{{Age: 10, Name: "Joe"},{Age: 12, Name: "John"}} }
    b, err := json.Marshal(user)
    if err != nil {
        fmt.Println(err)
        return
    }
     
    fmt.Println(string(b))
}

笔记

  1. 我正在使用这个站点: https://play.golang.org/来测试上面的代码。
  2. 如果 function 通过循环遍历所有结构字段来工作,那就太好了,因为在现实生活中,我有一个包含大约 30 个字段的结构,其中一些是具有嵌套结构的结构。

使用要编组的值构建 map。 使用反射 API 遍历结构中的字段并收集 map 中的值。 如果字段的值是切片或结构,则将该字段编码为 JSON 并在 map 中使用该值。 返回编码为 JSON 的 map。

func marshalFlat(value interface{}) ([]byte, error) {
    v := reflect.Indirect(reflect.ValueOf(value))
    t := v.Type()

    // Collect all fields in this map.
    m := make(map[string]interface{})
    for i := 0; i < t.NumField(); i++ {
        sf := t.Field(i)
        if sf.PkgPath != "" {
            // skip unexported
            continue
        }
        f := reflect.Indirect(v.Field(i))
        switch f.Kind() {
        case reflect.Slice, reflect.Struct:
            // Encode slices and structs as JSON and use
            // that JSON as the value of the field.
            p, err := json.Marshal(f.Interface())
            if err != nil {
                return nil, err
            }
            m[sf.Name] = string(p)
        default:
            // User other types as is.
            m[sf.Name] = f.Interface()
        }
    }
    return json.Marshal(m)
}

在操场上跑

只需实现 Marshaler 接口:)

package main

import (
    "encoding/json"
    "fmt"
    "strings"
)

type User struct {
    Name string `json:"name"`
    Friends Friends `json:"friends"`
    FavSnacks FavSnacks `json:"fav_snacks"`
}

type Friend struct {
    Age int `json:"age"`
    Name string `json:"name"`
}

type Friends []Friend

func (f *Friends) MarshalJSON() ([]byte, error) {
    type FriendsAux []Friend

    friendsAux := FriendsAux(*f)

    marshal, err := json.Marshal(friendsAux)
    if err != nil {
        return []byte{}, nil
    }
    escapedMarshal := strings.ReplaceAll(string(marshal), `"`, `'`)

    jsonToString := fmt.Sprintf(`"%s"`, escapedMarshal)

    return []byte(jsonToString), nil
}

type FavSnacks []string

func (f *FavSnacks) MarshalJSON() ([]byte, error) {
    type FavSnacksAux []string

    favSnacksAux := FavSnacksAux(*f)

    marshal, err := json.Marshal(favSnacksAux)
    if err != nil {
        return []byte{}, nil
    }
    escapedMarshal := strings.ReplaceAll(string(marshal), `"`, `'`)

    jsonToString := fmt.Sprintf(`"%s"`, escapedMarshal)

    return []byte(jsonToString), nil
}


func main() {
    user := &User{Name: "Frank", FavSnacks: []string{"apple","orange"}, Friends: []Friend{{Age: 10, Name: "Joe"},{Age: 12, Name: "John"}} }
    b, err := json.Marshal(user)
    if err != nil {
        fmt.Println(err)
        return
    }

    fmt.Println(string(b))
}

https://play.golang.org/p/gThG4mx0ogf

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM