-
Notifications
You must be signed in to change notification settings - Fork 0
/
clean.go
130 lines (119 loc) · 3.23 KB
/
clean.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package yamlutil
import (
"encoding/json"
"reflect"
)
// IsEmpty returns true if it is nil, "", 0, or its lenghth is zero.
func IsEmpty(it interface{}) bool {
if it == nil {
return true
}
t := reflect.TypeOf(it)
if t.Kind() == reflect.Slice ||
t.Kind() == reflect.Array ||
t.Kind() == reflect.Map ||
t.Kind() == reflect.Chan ||
t.Kind() == reflect.String {
return reflect.ValueOf(it).Len() == 0
} else if reflect.DeepEqual(it, reflect.Zero(t).Interface()) {
return true
} else if t.Kind() == reflect.Pointer {
return IsEmpty(reflect.ValueOf(it).Elem().Interface())
}
return false
}
// RemoveEmptyFromMap recursively removes empty values from a map.
func RemoveEmptyFromMap(it interface{}) interface{} {
mt, mv := reflect.TypeOf(it), reflect.ValueOf(it)
if mt.Kind() != reflect.Map || mv.Len() == 0 {
// If it is not a map, do nothing
if mt.Kind() == reflect.Slice || mt.Kind() == reflect.Array {
if mv.Len() == 0 {
return nil
}
newArr := reflect.New(mt)
for i := 0; i < mv.Len(); i++ {
vr, vt, vv := mv.Index(i), mv.Index(i).Type(), mv.Index(i).Interface()
_, _ = vr, vt
RemoveEmptyFromMap(vv)
if !IsEmpty(vv) {
newArr.Elem().Set(reflect.Append(newArr.Elem(), reflect.ValueOf(vv)))
}
}
return newArr.Interface()
}
return nil
}
iter := mv.MapRange()
for iter.Next() {
k := iter.Key()
v := iter.Value().Interface()
if IsEmpty(v) {
mv.SetMapIndex(k, reflect.Value{})
} else {
vt, vv := reflect.TypeOf(v), reflect.ValueOf(v)
if vt.Kind() == reflect.Map {
RemoveEmptyFromMap(v)
if vv.Len() == 0 {
mv.SetMapIndex(k, reflect.Value{})
}
} else if vt.Kind() == reflect.Ptr {
// is there a nil pointer in Go?
v = vv.Elem().Interface()
RemoveEmptyFromMap(v)
if IsEmpty(v) {
mv.SetMapIndex(k, reflect.Value{})
}
} else if vt.Kind() == reflect.Slice || vt.Kind() == reflect.Array {
v = RemoveEmptyFromMap(v)
if IsEmpty(v) {
mv.SetMapIndex(k, reflect.Value{})
} else {
mv.SetMapIndex(k, reflect.ValueOf(v))
}
}
}
}
return it
}
// RemoveEmptyAny marshals a given e into a string, unmarshal back to a map and then remove empty objects.
func RemoveEmptyAny(e interface{}) (map[string]interface{}, error) {
x, err := json.Marshal(e)
if err != nil {
return nil, err
}
z := map[string]interface{}{}
err = json.Unmarshal(x, &z)
if err != nil {
return nil, err
}
RemoveEmptyFromMap(z)
return z, nil
}
// MarshalJSONOmitEmptyIndented mashals a given value as a JSON omitting all empty values
func MarshalJSONOmitEmptyIndented(e interface{}) ([]byte, error) {
z, err := RemoveEmptyAny(e)
if err != nil {
return nil, err
}
return json.MarshalIndent(z, "", " ")
}
// MarshalJSONOmitEmpty mashals a given value as a JSON omitting all empty values
func MarshalJSONOmitEmpty(e interface{}) ([]byte, error) {
z, err := RemoveEmptyAny(e)
if err != nil {
return json.Marshal(e)
}
return json.Marshal(z)
}
// MustMarshalJSONOmitEmpty is a sugar version of MustMarshalJSONOmitEmpty.
func MustMarshalJSONOmitEmpty(e interface{}) string {
var v interface{}
if s, ok := e.(string); ok {
if err := json.Unmarshal([]byte(s), &v); err != nil {
e = v
}
}
z, _ := MarshalJSONOmitEmptyIndented(e)
return string(z)
}