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