77 | 77 |
|
78 | 78 |
//------------------------------------------------------------------------------
|
79 | 79 |
|
80 | |
func resolveJSONPointerHierarchy(path string) ([]string, error) {
|
|
80 |
// JSONPointerToSlice parses a JSON pointer path
|
|
81 |
// (https://tools.ietf.org/html/rfc6901) and returns the path segments as a
|
|
82 |
// slice.
|
|
83 |
//
|
|
84 |
// Because the characters '~' (%x7E) and '/' (%x2F) have special meanings in
|
|
85 |
// gabs paths, '~' needs to be encoded as '~0' and '/' needs to be encoded as
|
|
86 |
// '~1' when these characters appear in a reference key.
|
|
87 |
func JSONPointerToSlice(path string) ([]string, error) {
|
81 | 88 |
if len(path) < 1 {
|
82 | 89 |
return nil, errors.New("failed to resolve JSON pointer: path must not be empty")
|
83 | 90 |
}
|
|
93 | 100 |
return hierarchy, nil
|
94 | 101 |
}
|
95 | 102 |
|
96 | |
func resolveJSONDotPathHierarchy(path string) []string {
|
|
103 |
// DotPathToSlice returns a slice of path segments parsed out of a dot path.
|
|
104 |
//
|
|
105 |
// Because the characters '~' (%x7E) and '.' (%x2E) have special meanings in
|
|
106 |
// gabs paths, '~' needs to be encoded as '~0' and '.' needs to be encoded as
|
|
107 |
// '~1' when these characters appear in a reference key.
|
|
108 |
func DotPathToSlice(path string) []string {
|
97 | 109 |
hierarchy := strings.Split(path, ".")
|
98 | 110 |
for i, v := range hierarchy {
|
99 | 111 |
v = strings.Replace(v, "~1", ".", -1)
|
|
179 | 191 |
// gabs paths, '~' needs to be encoded as '~0' and '.' needs to be encoded as
|
180 | 192 |
// '~1' when these characters appear in a reference key.
|
181 | 193 |
func (g *Container) Path(path string) *Container {
|
182 | |
return g.Search(resolveJSONDotPathHierarchy(path)...)
|
|
194 |
return g.Search(DotPathToSlice(path)...)
|
183 | 195 |
}
|
184 | 196 |
|
185 | 197 |
// JSONPointer parses a JSON pointer path (https://tools.ietf.org/html/rfc6901)
|
|
190 | 202 |
// gabs paths, '~' needs to be encoded as '~0' and '/' needs to be encoded as
|
191 | 203 |
// '~1' when these characters appear in a reference key.
|
192 | 204 |
func (g *Container) JSONPointer(path string) (*Container, error) {
|
193 | |
hierarchy, err := resolveJSONPointerHierarchy(path)
|
|
205 |
hierarchy, err := JSONPointerToSlice(path)
|
194 | 206 |
if err != nil {
|
195 | 207 |
return nil, err
|
196 | 208 |
}
|
|
209 | 221 |
|
210 | 222 |
// ExistsP checks whether a dot notation path exists.
|
211 | 223 |
func (g *Container) ExistsP(path string) bool {
|
212 | |
return g.Exists(resolveJSONDotPathHierarchy(path)...)
|
|
224 |
return g.Exists(DotPathToSlice(path)...)
|
213 | 225 |
}
|
214 | 226 |
|
215 | 227 |
// Index attempts to find and return an element within a JSON array by an index.
|
|
332 | 344 |
// of the path that do not exist will be constructed, and if a collision occurs
|
333 | 345 |
// with a non object type whilst iterating the path an error is returned.
|
334 | 346 |
func (g *Container) SetP(value interface{}, path string) (*Container, error) {
|
335 | |
return g.Set(value, resolveJSONDotPathHierarchy(path)...)
|
|
347 |
return g.Set(value, DotPathToSlice(path)...)
|
336 | 348 |
}
|
337 | 349 |
|
338 | 350 |
// SetIndex attempts to set a value of an array element based on an index.
|
|
351 | 363 |
// (https://tools.ietf.org/html/rfc6901) and sets the leaf to a value. Returns
|
352 | 364 |
// an error if the pointer could not be resolved due to missing fields.
|
353 | 365 |
func (g *Container) SetJSONPointer(value interface{}, path string) (*Container, error) {
|
354 | |
hierarchy, err := resolveJSONPointerHierarchy(path)
|
|
366 |
hierarchy, err := JSONPointerToSlice(path)
|
355 | 367 |
if err != nil {
|
356 | 368 |
return nil, err
|
357 | 369 |
}
|
|
367 | 379 |
// ObjectP creates a new JSON object at a target path using dot notation.
|
368 | 380 |
// Returns an error if the path contains a collision with a non object type.
|
369 | 381 |
func (g *Container) ObjectP(path string) (*Container, error) {
|
370 | |
return g.Object(resolveJSONDotPathHierarchy(path)...)
|
|
382 |
return g.Object(DotPathToSlice(path)...)
|
371 | 383 |
}
|
372 | 384 |
|
373 | 385 |
// ObjectI creates a new JSON object at an array index. Returns an error if the
|
|
385 | 397 |
// ArrayP creates a new JSON array at a path using dot notation. Returns an
|
386 | 398 |
// error if the path contains a collision with a non object type.
|
387 | 399 |
func (g *Container) ArrayP(path string) (*Container, error) {
|
388 | |
return g.Array(resolveJSONDotPathHierarchy(path)...)
|
|
400 |
return g.Array(DotPathToSlice(path)...)
|
389 | 401 |
}
|
390 | 402 |
|
391 | 403 |
// ArrayI creates a new JSON array within an array at an index. Returns an error
|
|
405 | 417 |
// dot notation. Returns an error if the path contains a collision with a non
|
406 | 418 |
// object type.
|
407 | 419 |
func (g *Container) ArrayOfSizeP(size int, path string) (*Container, error) {
|
408 | |
return g.ArrayOfSize(size, resolveJSONDotPathHierarchy(path)...)
|
|
420 |
return g.ArrayOfSize(size, DotPathToSlice(path)...)
|
409 | 421 |
}
|
410 | 422 |
|
411 | 423 |
// ArrayOfSizeI create a new JSON array of a particular size within an array at
|
|
461 | 473 |
// DeleteP deletes an element at a path using dot notation, an error is returned
|
462 | 474 |
// if the element does not exist.
|
463 | 475 |
func (g *Container) DeleteP(path string) error {
|
464 | |
return g.Delete(resolveJSONDotPathHierarchy(path)...)
|
|
476 |
return g.Delete(DotPathToSlice(path)...)
|
465 | 477 |
}
|
466 | 478 |
|
467 | 479 |
// MergeFn merges two objects using a provided function to resolve collisions.
|
|
566 | 578 |
// notation. If the target is not a JSON array then it will be converted into
|
567 | 579 |
// one, with its original contents set to the first element of the array.
|
568 | 580 |
func (g *Container) ArrayAppendP(value interface{}, path string) error {
|
569 | |
return g.ArrayAppend(value, resolveJSONDotPathHierarchy(path)...)
|
|
581 |
return g.ArrayAppend(value, DotPathToSlice(path)...)
|
570 | 582 |
}
|
571 | 583 |
|
572 | 584 |
// ArrayRemove attempts to remove an element identified by an index from a JSON
|
|
591 | 603 |
// ArrayRemoveP attempts to remove an element identified by an index from a JSON
|
592 | 604 |
// array at a path using dot notation.
|
593 | 605 |
func (g *Container) ArrayRemoveP(index int, path string) error {
|
594 | |
return g.ArrayRemove(index, resolveJSONDotPathHierarchy(path)...)
|
|
606 |
return g.ArrayRemove(index, DotPathToSlice(path)...)
|
595 | 607 |
}
|
596 | 608 |
|
597 | 609 |
// ArrayElement attempts to access an element by an index from a JSON array at a
|
|
613 | 625 |
// ArrayElementP attempts to access an element by an index from a JSON array at
|
614 | 626 |
// a path using dot notation.
|
615 | 627 |
func (g *Container) ArrayElementP(index int, path string) (*Container, error) {
|
616 | |
return g.ArrayElement(index, resolveJSONDotPathHierarchy(path)...)
|
|
628 |
return g.ArrayElement(index, DotPathToSlice(path)...)
|
617 | 629 |
}
|
618 | 630 |
|
619 | 631 |
// ArrayCount counts the number of elements in a JSON array at a path.
|
|
627 | 639 |
// ArrayCountP counts the number of elements in a JSON array at a path using dot
|
628 | 640 |
// notation.
|
629 | 641 |
func (g *Container) ArrayCountP(path string) (int, error) {
|
630 | |
return g.ArrayCount(resolveJSONDotPathHierarchy(path)...)
|
|
642 |
return g.ArrayCount(DotPathToSlice(path)...)
|
631 | 643 |
}
|
632 | 644 |
|
633 | 645 |
//------------------------------------------------------------------------------
|
|
761 | 773 |
return &gabs, nil
|
762 | 774 |
}
|
763 | 775 |
|
|
776 |
// MarshalJSON returns the JSON encoding of this container. This allows
|
|
777 |
// structs which contain Container instances to be marshaled using
|
|
778 |
// json.Marshal().
|
|
779 |
func (g *Container) MarshalJSON() ([]byte, error) {
|
|
780 |
return json.Marshal(g.Data())
|
|
781 |
}
|
|
782 |
|
764 | 783 |
//------------------------------------------------------------------------------
|