github.com/TIBCOSoftware/flogo-lib@v0.5.9/core/mapper/exprmapper/json/gabs.go (about) 1 /* 2 Copyright (c) 2014 Ashley Jeffs 3 4 Permission is hereby granted, free of charge, to any person obtaining a copy 5 of this software and associated documentation files (the "Software"), to deal 6 in the Software without restriction, including without limitation the rights 7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 copies of the Software, and to permit persons to whom the Software is 9 furnished to do so, subject to the following conditions: 10 11 The above copyright notice and this permission notice shall be included in 12 all copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 THE SOFTWARE. 21 */ 22 23 // Package gabs implements a simplified wrapper around creating and parsing JSON. 24 package json 25 26 import ( 27 "encoding/json" 28 "errors" 29 "fmt" 30 "io" 31 "io/ioutil" 32 "reflect" 33 "strings" 34 ) 35 36 //-------------------------------------------------------------------------------------------------- 37 38 var ( 39 // ErrOutOfBounds - Index out of bounds. 40 ErrOutOfBounds = errors.New("out of bounds") 41 42 // ErrNotObjOrArray - The target is not an object or array type. 43 ErrNotObjOrArray = errors.New("not an object or array") 44 45 // ErrNotObj - The target is not an object type. 46 ErrNotObj = errors.New("not an object") 47 48 // ErrNotArray - The target is not an array type. 49 ErrNotArray = errors.New("not an array") 50 51 // ErrPathCollision - Creating a path failed because an element collided with an existing value. 52 ErrPathCollision = errors.New("encountered value collision whilst building path") 53 54 // ErrInvalidInputObj - The input value was not a map[string]interface{}. 55 ErrInvalidInputObj = errors.New("invalid input object") 56 57 // ErrInvalidInputText - The input data could not be parsed. 58 ErrInvalidInputText = errors.New("input text could not be parsed") 59 60 // ErrInvalidPath - The filepath was not valid. 61 ErrInvalidPath = errors.New("invalid file path") 62 63 // ErrInvalidBuffer - The input buffer contained an invalid JSON string 64 ErrInvalidBuffer = errors.New("input buffer contained invalid JSON") 65 ) 66 67 //-------------------------------------------------------------------------------------------------- 68 69 // Container - an internal structure that holds a reference to the core interface map of the parsed 70 // json. Use this container to move context. 71 type Container struct { 72 object interface{} 73 } 74 75 // Data - Return the contained data as an interface{}. 76 func (g *Container) Data() interface{} { 77 return g.object 78 } 79 80 //-------------------------------------------------------------------------------------------------- 81 82 // Path - Search for a value using dot notation. 83 func (g *Container) Path(path string) *Container { 84 return g.Search(strings.Split(path, ".")...) 85 } 86 87 // Search - Attempt to find and return an object within the JSON structure by specifying the 88 // hierarchy of field names to locate the target. If the search encounters an array and has not 89 // reached the end target then it will iterate each object of the array for the target and return 90 // all of the results in a JSON array. 91 func (g *Container) Search(hierarchy ...string) *Container { 92 var object interface{} 93 94 object = g.object 95 for target := 0; target < len(hierarchy); target++ { 96 if mmap, ok := object.(map[string]string); ok { 97 object = mmap[hierarchy[target]] 98 } else if mmap, ok := object.(map[string]interface{}); ok { 99 object = mmap[hierarchy[target]] 100 } else if marray, ok := object.([]interface{}); ok { 101 tmpArray := []interface{}{} 102 for _, val := range marray { 103 tmpGabs := &Container{val} 104 res := tmpGabs.Search(hierarchy[target:]...).Data() 105 if res != nil { 106 tmpArray = append(tmpArray, res) 107 } 108 } 109 if len(tmpArray) == 0 { 110 return &Container{nil} 111 } 112 return &Container{tmpArray} 113 } else { 114 if object != nil { 115 fmt.Println(reflect.TypeOf(object).Kind().String()) 116 //if reflect.TypeOf(object).Kind() == reflect.Struct { 117 field, err := GetFieldByName(object, hierarchy[target]) 118 if err != nil { 119 log.Errorf("no field name [%s] found in [%+v]", hierarchy[target], object) 120 return &Container{nil} 121 } 122 return &Container{field.Interface()} 123 //} 124 } 125 return &Container{nil} 126 127 } 128 } 129 return &Container{object} 130 } 131 132 // S - Shorthand method, does the same thing as Search. 133 func (g *Container) S(hierarchy ...string) *Container { 134 return g.Search(hierarchy...) 135 } 136 137 // Exists - Checks whether a path exists. 138 func (g *Container) Exists(hierarchy ...string) bool { 139 return g.Search(hierarchy...).Data() != nil 140 } 141 142 // ExistsP - Checks whether a dot notation path exists. 143 func (g *Container) ExistsP(path string) bool { 144 return g.Exists(strings.Split(path, ".")...) 145 } 146 147 // Index - Attempt to find and return an object within a JSON array by index. 148 func (g *Container) Index(index int) *Container { 149 if array, ok := g.Data().([]interface{}); ok { 150 if index >= len(array) { 151 return &Container{nil} 152 } 153 return &Container{array[index]} 154 } 155 return &Container{nil} 156 } 157 158 // Children - Return a slice of all the children of the array. This also works for objects, however, 159 // the children returned for an object will NOT be in order and you lose the names of the returned 160 // objects this way. 161 func (g *Container) Children() ([]*Container, error) { 162 if array, ok := g.Data().([]interface{}); ok { 163 children := make([]*Container, len(array)) 164 for i := 0; i < len(array); i++ { 165 children[i] = &Container{array[i]} 166 } 167 return children, nil 168 } 169 if mmap, ok := g.Data().(map[string]interface{}); ok { 170 children := []*Container{} 171 for _, obj := range mmap { 172 children = append(children, &Container{obj}) 173 } 174 return children, nil 175 } else if mmap, ok := g.Data().(map[string]string); ok { 176 children := []*Container{} 177 for _, obj := range mmap { 178 children = append(children, &Container{obj}) 179 } 180 return children, nil 181 } 182 return nil, ErrNotObjOrArray 183 } 184 185 // ChildrenMap - Return a map of all the children of an object. 186 func (g *Container) ChildrenMap() (map[string]*Container, error) { 187 if mmap, ok := g.Data().(map[string]interface{}); ok { 188 children := map[string]*Container{} 189 for name, obj := range mmap { 190 children[name] = &Container{obj} 191 } 192 return children, nil 193 } else if mmap, ok := g.Data().(map[string]string); ok { 194 children := map[string]*Container{} 195 for name, obj := range mmap { 196 children[name] = &Container{obj} 197 } 198 return children, nil 199 } 200 return nil, ErrNotObj 201 } 202 203 //-------------------------------------------------------------------------------------------------- 204 205 // Set - Set the value of a field at a JSON path, any parts of the path that do not exist will be 206 // constructed, and if a collision occurs with a non object type whilst iterating the path an error 207 // is returned. 208 func (g *Container) Set(value interface{}, path ...string) (*Container, error) { 209 if len(path) == 0 { 210 g.object = value 211 return g, nil 212 } 213 var object interface{} 214 if g.object == nil { 215 g.object = map[string]interface{}{} 216 } 217 object = g.object 218 for target := 0; target < len(path); target++ { 219 if mmap, ok := object.(map[string]interface{}); ok { 220 if target == len(path)-1 { 221 mmap[path[target]] = value 222 } else if mmap[path[target]] == nil { 223 mmap[path[target]] = map[string]interface{}{} 224 } 225 object = mmap[path[target]] 226 } else if mmap, ok := object.(map[string]string); ok { 227 if target == len(path)-1 { 228 v, ok := value.(string) 229 if !ok { 230 return &Container{nil}, fmt.Errorf("convert [%+v] to string failed", value) 231 } 232 mmap[path[target]] = v 233 } else if mmap[path[target]] == "" { 234 mmap[path[target]] = "" 235 } 236 object = mmap[path[target]] 237 } else { 238 field, err := GetFieldByName(object, path[target]) 239 if target == len(path)-1 { 240 if err != nil { 241 return &Container{nil}, fmt.Errorf("not found name [%s] in struct [%+v]", path[target], field) 242 } 243 field.Set(reflect.ValueOf(value)) 244 } else { 245 if err != nil { 246 return &Container{nil}, fmt.Errorf("not found name [%s] in struct [%+v]", path[target], field) 247 } 248 249 if field.Interface() == nil { 250 field.Set(reflect.New(field.Type())) 251 } 252 } 253 object = field 254 255 } 256 } 257 return &Container{object}, nil 258 } 259 260 // SetP - Does the same as Set, but using a dot notation JSON path. 261 func (g *Container) SetP(value interface{}, path string) (*Container, error) { 262 return g.Set(value, strings.Split(path, ".")...) 263 } 264 265 // SetIndex - Set a value of an array element based on the index. 266 func (g *Container) SetIndex(value interface{}, index int) (*Container, error) { 267 if array, ok := g.Data().([]interface{}); ok { 268 if index >= len(array) { 269 return &Container{nil}, ErrOutOfBounds 270 } 271 array[index] = value 272 return &Container{array[index]}, nil 273 } 274 return &Container{nil}, ErrNotArray 275 } 276 277 // Object - Create a new JSON object at a path. Returns an error if the path contains a collision 278 // with a non object type. 279 func (g *Container) Object(path ...string) (*Container, error) { 280 return g.Set(map[string]interface{}{}, path...) 281 } 282 283 // ObjectP - Does the same as Object, but using a dot notation JSON path. 284 func (g *Container) ObjectP(path string) (*Container, error) { 285 return g.Object(strings.Split(path, ".")...) 286 } 287 288 // ObjectI - Create a new JSON object at an array index. Returns an error if the object is not an 289 // array or the index is out of bounds. 290 func (g *Container) ObjectI(index int) (*Container, error) { 291 return g.SetIndex(map[string]interface{}{}, index) 292 } 293 294 // Array - Create a new JSON array at a path. Returns an error if the path contains a collision with 295 // a non object type. 296 func (g *Container) Array(path ...string) (*Container, error) { 297 return g.Set([]interface{}{}, path...) 298 } 299 300 // ArrayP - Does the same as Array, but using a dot notation JSON path. 301 func (g *Container) ArrayP(path string) (*Container, error) { 302 return g.Array(strings.Split(path, ".")...) 303 } 304 305 // ArrayI - Create a new JSON array at an array index. Returns an error if the object is not an 306 // array or the index is out of bounds. 307 func (g *Container) ArrayI(index int) (*Container, error) { 308 return g.SetIndex([]interface{}{}, index) 309 } 310 311 // ArrayOfSize - Create a new JSON array of a particular size at a path. Returns an error if the 312 // path contains a collision with a non object type. 313 func (g *Container) ArrayOfSize(size int, path ...string) (*Container, error) { 314 a := make([]interface{}, size) 315 return g.Set(a, path...) 316 } 317 318 // ArrayOfSizeP - Does the same as ArrayOfSize, but using a dot notation JSON path. 319 func (g *Container) ArrayOfSizeP(size int, path string) (*Container, error) { 320 return g.ArrayOfSize(size, strings.Split(path, ".")...) 321 } 322 323 // ArrayOfSizeI - Create a new JSON array of a particular size at an array index. Returns an error 324 // if the object is not an array or the index is out of bounds. 325 func (g *Container) ArrayOfSizeI(size, index int) (*Container, error) { 326 a := make([]interface{}, size) 327 return g.SetIndex(a, index) 328 } 329 330 // Delete - Delete an element at a JSON path, an error is returned if the element does not exist. 331 func (g *Container) Delete(path ...string) error { 332 var object interface{} 333 334 if g.object == nil { 335 return ErrNotObj 336 } 337 object = g.object 338 for target := 0; target < len(path); target++ { 339 if mmap, ok := object.(map[string]interface{}); ok { 340 if target == len(path)-1 { 341 if _, ok := mmap[path[target]]; ok { 342 delete(mmap, path[target]) 343 } else { 344 return ErrNotObj 345 } 346 } 347 object = mmap[path[target]] 348 } else if mmap, ok := object.(map[string]string); ok { 349 if target == len(path)-1 { 350 if _, ok := mmap[path[target]]; ok { 351 delete(mmap, path[target]) 352 } else { 353 return ErrNotObj 354 } 355 } 356 object = mmap[path[target]] 357 } else { 358 return ErrNotObj 359 } 360 } 361 return nil 362 } 363 364 // DeleteP - Does the same as Delete, but using a dot notation JSON path. 365 func (g *Container) DeleteP(path string) error { 366 return g.Delete(strings.Split(path, ".")...) 367 } 368 369 //-------------------------------------------------------------------------------------------------- 370 371 /* 372 Array modification/search - Keeping these options simple right now, no need for anything more 373 complicated since you can just cast to []interface{}, modify and then reassign with Set. 374 */ 375 376 // ArrayAppend - Append a value onto a JSON array. 377 func (g *Container) ArrayAppend(value interface{}, path ...string) error { 378 array, ok := g.Search(path...).Data().([]interface{}) 379 if !ok { 380 return ErrNotArray 381 } 382 array = append(array, value) 383 _, err := g.Set(array, path...) 384 return err 385 } 386 387 // ArrayAppendP - Append a value onto a JSON array using a dot notation JSON path. 388 func (g *Container) ArrayAppendP(value interface{}, path string) error { 389 return g.ArrayAppend(value, strings.Split(path, ".")...) 390 } 391 392 // ArrayRemove - Remove an element from a JSON array. 393 func (g *Container) ArrayRemove(index int, path ...string) error { 394 if index < 0 { 395 return ErrOutOfBounds 396 } 397 array, ok := g.Search(path...).Data().([]interface{}) 398 if !ok { 399 return ErrNotArray 400 } 401 if index < len(array) { 402 array = append(array[:index], array[index+1:]...) 403 } else { 404 return ErrOutOfBounds 405 } 406 _, err := g.Set(array, path...) 407 return err 408 } 409 410 // ArrayRemoveP - Remove an element from a JSON array using a dot notation JSON path. 411 func (g *Container) ArrayRemoveP(index int, path string) error { 412 return g.ArrayRemove(index, strings.Split(path, ".")...) 413 } 414 415 // ArrayElement - Access an element from a JSON array. 416 func (g *Container) ArrayElement(index int, path ...string) (*Container, error) { 417 if index < 0 { 418 return &Container{nil}, ErrOutOfBounds 419 } 420 array, ok := g.Search(path...).Data().([]interface{}) 421 if !ok { 422 //Convert to array 423 var err error 424 array, err = ToArray(g.Search(path...).Data()) 425 if err != nil { 426 return &Container{nil}, ErrNotArray 427 } 428 } 429 if index < len(array) { 430 return &Container{array[index]}, nil 431 } 432 return &Container{nil}, ErrOutOfBounds 433 } 434 435 // ArrayElementP - Access an element from a JSON array using a dot notation JSON path. 436 func (g *Container) ArrayElementP(index int, path string) (*Container, error) { 437 return g.ArrayElement(index, strings.Split(path, ".")...) 438 } 439 440 // ArrayCount - Count the number of elements in a JSON array. 441 func (g *Container) ArrayCount(path ...string) (int, error) { 442 if array, ok := g.Search(path...).Data().([]interface{}); ok { 443 return len(array), nil 444 } 445 return 0, ErrNotArray 446 } 447 448 // ArrayCountP - Count the number of elements in a JSON array using a dot notation JSON path. 449 func (g *Container) ArrayCountP(path string) (int, error) { 450 return g.ArrayCount(strings.Split(path, ".")...) 451 } 452 453 //-------------------------------------------------------------------------------------------------- 454 455 // Bytes - Converts the contained object back to a JSON []byte blob. 456 func (g *Container) Bytes() []byte { 457 if g.object != nil { 458 if bytes, err := json.Marshal(g.object); err == nil { 459 return bytes 460 } 461 } 462 return []byte("{}") 463 } 464 465 // BytesIndent - Converts the contained object to a JSON []byte blob formatted with prefix, indent. 466 func (g *Container) BytesIndent(prefix string, indent string) []byte { 467 if g.object != nil { 468 if bytes, err := json.MarshalIndent(g.object, prefix, indent); err == nil { 469 return bytes 470 } 471 } 472 return []byte("{}") 473 } 474 475 // String - Converts the contained object to a JSON formatted string. 476 func (g *Container) String() string { 477 return string(g.Bytes()) 478 } 479 480 // StringIndent - Converts the contained object back to a JSON formatted string with prefix, indent. 481 func (g *Container) StringIndent(prefix string, indent string) string { 482 return string(g.BytesIndent(prefix, indent)) 483 } 484 485 // New - Create a new gabs JSON object. 486 func New() *Container { 487 return &Container{map[string]interface{}{}} 488 } 489 490 // Consume - Gobble up an already converted JSON object, or a fresh map[string]interface{} object. 491 func Consume(root interface{}) (*Container, error) { 492 return &Container{root}, nil 493 } 494 495 // ParseJSON - Convert a string into a representation of the parsed JSON. 496 func ParseJSON(sample []byte) (*Container, error) { 497 var gabs Container 498 499 if err := json.Unmarshal(sample, &gabs.object); err != nil { 500 return nil, err 501 } 502 503 return &gabs, nil 504 } 505 506 // ParseJSONDecoder - Convert a json.Decoder into a representation of the parsed JSON. 507 func ParseJSONDecoder(decoder *json.Decoder) (*Container, error) { 508 var gabs Container 509 510 if err := decoder.Decode(&gabs.object); err != nil { 511 return nil, err 512 } 513 514 return &gabs, nil 515 } 516 517 // ParseJSONFile - Read a file and convert into a representation of the parsed JSON. 518 func ParseJSONFile(path string) (*Container, error) { 519 if len(path) > 0 { 520 cBytes, err := ioutil.ReadFile(path) 521 if err != nil { 522 return nil, err 523 } 524 525 container, err := ParseJSON(cBytes) 526 if err != nil { 527 return nil, err 528 } 529 530 return container, nil 531 } 532 return nil, ErrInvalidPath 533 } 534 535 // ParseJSONBuffer - Read the contents of a buffer into a representation of the parsed JSON. 536 func ParseJSONBuffer(buffer io.Reader) (*Container, error) { 537 var gabs Container 538 jsonDecoder := json.NewDecoder(buffer) 539 if err := jsonDecoder.Decode(&gabs.object); err != nil { 540 return nil, err 541 } 542 543 return &gabs, nil 544 } 545 546 //--------------------------------------------------------------------------------------------------