Background
I have a struct that I have been passing to users as a json via an API. This works.
I am now trying to send the same struct as an object that my UI can easily convert to a csv and allow the user to download.
I have code that works on the UI to convert simple objects to a CSV. So I can send an object where the values are just integers or strings no problem. But, my struct has values that are objects and arrays. So, I am trying to find a way to convert my complex json object to a simpler one. The simpler object should only have values with either no quotes like an int or just one set of quotes on the outside like a string.
Question
How do I convert a golang struct into a json that has "simple" values (string, bool, int but not array or object with more quotes)?
Example
For instance this code converts user to a json with the formatting:
{
"Name":"Frank",
"Friends":[{"Age":10,"Name":"Joe"}, {"Age":12,"Name":"John"}],
"FavSnacks":["apple","orange"]
}
, but I would like the formatting
{
"Name":"Frank",
"Friends":"[{'Age':10,'Name':'Joe'},{'Age':12,'Name':'John'}]",
"FavSnacks":"['apple','orange']"
}
or
{
"Name":"Frank",
"Friends":"[{Age:10, Name:Joe},{Age:12,Name:John}]",
"FavSnacks":"[apple, orange]"
}
Here is the code I have
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))
}
Notes
Build a map with the values you want to marshal. Use the reflect API to iterate through the fields in the struct and collect the values in a map. If the value of the field is a slice or struct, then encode the field to JSON and use that value in the map. Return the map encoded to JSON.
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)
}
Just implement Marshaler interface:)
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))
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.