github.com/zhongdalu/gf@v1.0.0/g/encoding/gjson/gjson.go (about) 1 // Copyright 2017 gf Author(https://github.com/zhongdalu/gf). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/zhongdalu/gf. 6 7 // Package gjson provides convenient API for JSON/XML/YAML/TOML data handling. 8 package gjson 9 10 import ( 11 "reflect" 12 "strconv" 13 "strings" 14 15 "github.com/zhongdalu/gf/g/internal/rwmutex" 16 "github.com/zhongdalu/gf/g/text/gstr" 17 "github.com/zhongdalu/gf/g/util/gconv" 18 ) 19 20 const ( 21 // Separator char for hierarchical data access. 22 gDEFAULT_SPLIT_CHAR = '.' 23 ) 24 25 // The customized JSON struct. 26 type Json struct { 27 mu *rwmutex.RWMutex 28 p *interface{} // Pointer for hierarchical data access, it's the root of data in default. 29 c byte // Char separator('.' in default). 30 vc bool // Violence Check(false in default), which is used to access data when the hierarchical data key contains separator char. 31 } 32 33 // MarshalJSON implements the interface MarshalJSON for json.Marshal. 34 func (j *Json) MarshalJSON() ([]byte, error) { 35 return j.ToJson() 36 } 37 38 // setValue sets <value> to <j> by <pattern>. 39 // Note: 40 // 1. If value is nil and removed is true, means deleting this value; 41 // 2. It's quite complicated in hierarchical data search, node creating and data assignment; 42 func (j *Json) setValue(pattern string, value interface{}, removed bool) error { 43 array := strings.Split(pattern, string(j.c)) 44 length := len(array) 45 value = j.convertValue(value) 46 // 初始化判断 47 if *j.p == nil { 48 if gstr.IsNumeric(array[0]) { 49 *j.p = make([]interface{}, 0) 50 } else { 51 *j.p = make(map[string]interface{}) 52 } 53 } 54 var pparent *interface{} = nil // Parent pointer. 55 var pointer *interface{} = j.p // Current pointer. 56 j.mu.Lock() 57 defer j.mu.Unlock() 58 for i := 0; i < length; i++ { 59 switch (*pointer).(type) { 60 case map[string]interface{}: 61 if i == length-1 { 62 if removed && value == nil { 63 // Delete item from map. 64 delete((*pointer).(map[string]interface{}), array[i]) 65 } else { 66 (*pointer).(map[string]interface{})[array[i]] = value 67 } 68 } else { 69 // If the key does not exit in the map. 70 if v, ok := (*pointer).(map[string]interface{})[array[i]]; !ok { 71 if removed && value == nil { 72 goto done 73 } 74 // Creating new node. 75 if gstr.IsNumeric(array[i+1]) { 76 // Creating array node. 77 n, _ := strconv.Atoi(array[i+1]) 78 var v interface{} = make([]interface{}, n+1) 79 pparent = j.setPointerWithValue(pointer, array[i], v) 80 pointer = &v 81 } else { 82 // Creating map node. 83 var v interface{} = make(map[string]interface{}) 84 pparent = j.setPointerWithValue(pointer, array[i], v) 85 pointer = &v 86 } 87 } else { 88 pparent = pointer 89 pointer = &v 90 } 91 } 92 93 case []interface{}: 94 if !gstr.IsNumeric(array[i]) { 95 if i == length-1 { 96 *pointer = map[string]interface{}{array[i]: value} 97 } else { 98 var v interface{} = make(map[string]interface{}) 99 *pointer = v 100 pparent = pointer 101 pointer = &v 102 } 103 continue 104 } 105 106 valn, err := strconv.Atoi(array[i]) 107 if err != nil { 108 return err 109 } 110 // Leaf node. 111 if i == length-1 { 112 if len((*pointer).([]interface{})) > valn { 113 if removed && value == nil { 114 // Deleting element. 115 if pparent == nil { 116 *pointer = append((*pointer).([]interface{})[:valn], (*pointer).([]interface{})[valn+1:]...) 117 } else { 118 j.setPointerWithValue(pparent, array[i-1], append((*pointer).([]interface{})[:valn], (*pointer).([]interface{})[valn+1:]...)) 119 } 120 } else { 121 (*pointer).([]interface{})[valn] = value 122 } 123 } else { 124 if removed && value == nil { 125 goto done 126 } 127 if pparent == nil { 128 // It is the root node. 129 j.setPointerWithValue(pointer, array[i], value) 130 } else { 131 // It is not the root node. 132 s := make([]interface{}, valn+1) 133 copy(s, (*pointer).([]interface{})) 134 s[valn] = value 135 j.setPointerWithValue(pparent, array[i-1], s) 136 } 137 } 138 } else { 139 if gstr.IsNumeric(array[i+1]) { 140 n, _ := strconv.Atoi(array[i+1]) 141 if len((*pointer).([]interface{})) > valn { 142 (*pointer).([]interface{})[valn] = make([]interface{}, n+1) 143 pparent = pointer 144 pointer = &(*pointer).([]interface{})[valn] 145 } else { 146 if removed && value == nil { 147 goto done 148 } 149 var v interface{} = make([]interface{}, n+1) 150 pparent = j.setPointerWithValue(pointer, array[i], v) 151 pointer = &v 152 } 153 } else { 154 var v interface{} = make(map[string]interface{}) 155 pparent = j.setPointerWithValue(pointer, array[i], v) 156 pointer = &v 157 } 158 } 159 160 // If the variable pointed to by the <pointer> is not of a reference type, 161 // then it modifies the variable via its the parent, ie: pparent. 162 default: 163 if removed && value == nil { 164 goto done 165 } 166 if gstr.IsNumeric(array[i]) { 167 n, _ := strconv.Atoi(array[i]) 168 s := make([]interface{}, n+1) 169 if i == length-1 { 170 s[n] = value 171 } 172 if pparent != nil { 173 pparent = j.setPointerWithValue(pparent, array[i-1], s) 174 } else { 175 *pointer = s 176 pparent = pointer 177 } 178 } else { 179 var v interface{} = make(map[string]interface{}) 180 if i == length-1 { 181 v = map[string]interface{}{ 182 array[i]: value, 183 } 184 } 185 if pparent != nil { 186 pparent = j.setPointerWithValue(pparent, array[i-1], v) 187 } else { 188 *pointer = v 189 pparent = pointer 190 } 191 pointer = &v 192 } 193 } 194 } 195 done: 196 return nil 197 } 198 199 // convertValue converts <value> to map[string]interface{} or []interface{}, 200 // which can be supported for hierarchical data access. 201 func (j *Json) convertValue(value interface{}) interface{} { 202 switch value.(type) { 203 case map[string]interface{}: 204 return value 205 case []interface{}: 206 return value 207 default: 208 rv := reflect.ValueOf(value) 209 kind := rv.Kind() 210 if kind == reflect.Ptr { 211 rv = rv.Elem() 212 kind = rv.Kind() 213 } 214 switch kind { 215 case reflect.Array: 216 return gconv.Interfaces(value) 217 case reflect.Slice: 218 return gconv.Interfaces(value) 219 case reflect.Map: 220 return gconv.Map(value) 221 case reflect.Struct: 222 return gconv.Map(value) 223 default: 224 // Use json decode/encode at last. 225 b, _ := Encode(value) 226 v, _ := Decode(b) 227 return v 228 } 229 } 230 } 231 232 // setPointerWithValue sets <key>:<value> to <pointer>, the <key> may be a map key or slice index. 233 // It returns the pointer to the new value set. 234 func (j *Json) setPointerWithValue(pointer *interface{}, key string, value interface{}) *interface{} { 235 switch (*pointer).(type) { 236 case map[string]interface{}: 237 (*pointer).(map[string]interface{})[key] = value 238 return &value 239 case []interface{}: 240 n, _ := strconv.Atoi(key) 241 if len((*pointer).([]interface{})) > n { 242 (*pointer).([]interface{})[n] = value 243 return &(*pointer).([]interface{})[n] 244 } else { 245 s := make([]interface{}, n+1) 246 copy(s, (*pointer).([]interface{})) 247 s[n] = value 248 *pointer = s 249 return &s[n] 250 } 251 default: 252 *pointer = value 253 } 254 return pointer 255 } 256 257 // getPointerByPattern returns a pointer to the value by specified <pattern>. 258 func (j *Json) getPointerByPattern(pattern string) *interface{} { 259 if j.vc { 260 return j.getPointerByPatternWithViolenceCheck(pattern) 261 } else { 262 return j.getPointerByPatternWithoutViolenceCheck(pattern) 263 } 264 } 265 266 // getPointerByPatternWithViolenceCheck returns a pointer to the value of specified <pattern> with violence check. 267 func (j *Json) getPointerByPatternWithViolenceCheck(pattern string) *interface{} { 268 if !j.vc { 269 return j.getPointerByPatternWithoutViolenceCheck(pattern) 270 } 271 index := len(pattern) 272 start := 0 273 length := 0 274 pointer := j.p 275 if index == 0 { 276 return pointer 277 } 278 for { 279 if r := j.checkPatternByPointer(pattern[start:index], pointer); r != nil { 280 length += index - start 281 if start > 0 { 282 length += 1 283 } 284 start = index + 1 285 index = len(pattern) 286 if length == len(pattern) { 287 return r 288 } else { 289 pointer = r 290 } 291 } else { 292 // Get the position for next separator char. 293 index = strings.LastIndexByte(pattern[start:index], j.c) 294 if index != -1 && length > 0 { 295 index += length + 1 296 } 297 } 298 if start >= index { 299 break 300 } 301 } 302 return nil 303 } 304 305 // getPointerByPatternWithoutViolenceCheck returns a pointer to the value of specified <pattern>, with no violence check. 306 func (j *Json) getPointerByPatternWithoutViolenceCheck(pattern string) *interface{} { 307 if j.vc { 308 return j.getPointerByPatternWithViolenceCheck(pattern) 309 } 310 pointer := j.p 311 if len(pattern) == 0 { 312 return pointer 313 } 314 array := strings.Split(pattern, string(j.c)) 315 for k, v := range array { 316 if r := j.checkPatternByPointer(v, pointer); r != nil { 317 if k == len(array)-1 { 318 return r 319 } else { 320 pointer = r 321 } 322 } else { 323 break 324 } 325 } 326 return nil 327 } 328 329 // checkPatternByPointer checks whether there's value by <key> in specified <pointer>. 330 // It returns a pointer to the value. 331 func (j *Json) checkPatternByPointer(key string, pointer *interface{}) *interface{} { 332 switch (*pointer).(type) { 333 case map[string]interface{}: 334 if v, ok := (*pointer).(map[string]interface{})[key]; ok { 335 return &v 336 } 337 case []interface{}: 338 if gstr.IsNumeric(key) { 339 n, err := strconv.Atoi(key) 340 if err == nil && len((*pointer).([]interface{})) > n { 341 return &(*pointer).([]interface{})[n] 342 } 343 } 344 } 345 return nil 346 }