-
Notifications
You must be signed in to change notification settings - Fork 0
/
parse.go
174 lines (157 loc) · 4.62 KB
/
parse.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package json_configs
import (
"fmt"
"reflect"
"strconv"
"time"
)
// Parse config dataMap entries corresponding to data object (st, sv) fields
func parseConfig(st reflect.Type, sv reflect.Value, parsedMap ParsedMap, errList *[]string) (resultMap ResultMap) {
var err error
var elementId, filename, tagName, paramValue, paramType string
var v interface{}
var parsedArr []Parsed
var dur time.Duration
var date time.Time
var f float64
var n int64
var i int
var ok, clear bool
// Map for json param names to tag names
param2tag := make(map[string]string)
for i = 0; i < st.NumField(); i++ {
param := st.Field(i)
tagName, ok = param.Tag.Lookup("json")
if ok {
param2tag[param.Name] = tagName
}
}
// If multiple results, we will have to clear 'data' object each iteration
clear = len(parsedMap) > 1
resultMap = make(ResultMap)
for elementId, parsedArr = range parsedMap {
// Make map of parameter names that will need to be reset after parsing element
clearParamMap := make(map[string]bool)
for _, parsed := range parsedArr {
if parsed.Position == 0 {
filename = parsed.DistinctName
} else {
filename = fmt.Sprintf("%s:elem#%d", parsed.DistinctName, parsed.Position)
}
// Iterate through element data fields, parse into correct type
for i = 0; i < st.NumField(); i++ {
param := st.Field(i)
// lookup in ElementMap by tag name first, then by param name
tagName, ok = param2tag[param.Name]
if ok {
v, ok = parsed.ElementMap[tagName]
}
if !ok {
v, ok = parsed.ElementMap[param.Name]
}
if ok {
paramValue = fmt.Sprintf("%v", v)
paramType = param.Type.Name()
clearParamMap[param.Name] = true
switch paramType {
case "string":
sv.Field(i).SetString(paramValue)
case "float64":
f, err = strconv.ParseFloat(paramValue, 64)
if err != nil {
*errList = append(*errList,
fmt.Sprintf("setting for %s invalid, parameter %s: float %s [%s]",
elementId, param.Name, paramValue, filename))
continue
}
sv.Field(i).SetFloat(f)
case "int", "int64":
n, err = strconv.ParseInt(paramValue, 10, 64)
if err != nil {
*errList = append(*errList,
fmt.Sprintf("setting for %s invalid, parameter %s: integer %s [%s]",
elementId, param.Name, paramValue, filename))
continue
}
sv.Field(i).SetInt(n)
case "bool":
ok, err = strconv.ParseBool(paramValue)
if err != nil {
*errList = append(*errList,
fmt.Sprintf("setting for %s invalid, parameter %s: boolean %s [%s]",
elementId, param.Name, paramValue, filename))
continue
}
sv.Field(i).SetBool(ok)
case "Duration":
dur, err = time.ParseDuration(paramValue)
if err != nil {
*errList = append(*errList,
fmt.Sprintf("setting for %s invalid, parameter %s: duration %s [%s]",
elementId, param.Name, paramValue, filename))
continue
}
sv.Field(i).Set(reflect.ValueOf(dur))
case "Time":
date, err = time.Parse("2006-01-02T15:04:05Z", paramValue)
if err != nil {
date, err = time.Parse("2006-01-02", paramValue)
}
if err != nil {
*errList = append(*errList,
fmt.Sprintf("setting for %s invalid, parameter %s: date %s [%s]",
elementId, param.Name, paramValue, filename))
continue
}
sv.Field(i).Set(reflect.ValueOf(date))
default:
*errList = append(*errList,
fmt.Sprintf("setting for %s invalid, parameter %s: unsupported type %s [%s]",
elementId, param.Name, paramType, filename))
continue
}
}
}
}
// Store data object in resultMap
resultMap[elementId] = sv.Interface()
// Clear data object for next element Id
if clear {
clearConfig(st, sv, clearParamMap)
}
}
return
}
func clearConfig(st reflect.Type, sv reflect.Value, clearParamMap map[string]bool) (err error) {
var paramType string
var zeroD time.Duration
var zeroT time.Time
var i int
var ok bool
// Iterate through data fields, clear settings
for i = 0; i < st.NumField(); i++ {
param := st.Field(i)
ok = clearParamMap[param.Name]
if ok {
paramType = param.Type.Name()
switch paramType {
case "string":
sv.Field(i).SetString("")
case "float64":
sv.Field(i).SetFloat(0)
case "int", "int64":
sv.Field(i).SetInt(0)
case "bool":
sv.Field(i).SetBool(false)
case "Duration":
sv.Field(i).Set(reflect.ValueOf(zeroD))
case "Time":
sv.Field(i).Set(reflect.ValueOf(zeroT))
default:
err = fmt.Errorf("unsupported type %s [%s]", paramType, param.Name)
return
}
}
}
return
}