Codebase list golang-github-jeffail-gabs / 879ab37
Update upstream source from tag 'upstream/2.3.0' Update to upstream version '2.3.0' with Debian dir 5b018bfca9c9f3f23c62494b82520a306a895b31 Dawid Dziurla 4 years ago
4 changed file(s) with 56 addition(s) and 16 deletion(s). Raw diff Collapse all Expand all
0 # These are supported funding model platforms
1
2 github: Jeffail
121121 if err != nil {
122122 panic(err)
123123 }
124 fmt.Println(jsonParsed.Path("array.value.1").String())
124 fmt.Println(jsonParsed.Path("array.1.value").String())
125125 ```
126126
127127 Will print `2`.
7777
7878 //------------------------------------------------------------------------------
7979
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) {
8188 if len(path) < 1 {
8289 return nil, errors.New("failed to resolve JSON pointer: path must not be empty")
8390 }
93100 return hierarchy, nil
94101 }
95102
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 {
97109 hierarchy := strings.Split(path, ".")
98110 for i, v := range hierarchy {
99111 v = strings.Replace(v, "~1", ".", -1)
179191 // gabs paths, '~' needs to be encoded as '~0' and '.' needs to be encoded as
180192 // '~1' when these characters appear in a reference key.
181193 func (g *Container) Path(path string) *Container {
182 return g.Search(resolveJSONDotPathHierarchy(path)...)
194 return g.Search(DotPathToSlice(path)...)
183195 }
184196
185197 // JSONPointer parses a JSON pointer path (https://tools.ietf.org/html/rfc6901)
190202 // gabs paths, '~' needs to be encoded as '~0' and '/' needs to be encoded as
191203 // '~1' when these characters appear in a reference key.
192204 func (g *Container) JSONPointer(path string) (*Container, error) {
193 hierarchy, err := resolveJSONPointerHierarchy(path)
205 hierarchy, err := JSONPointerToSlice(path)
194206 if err != nil {
195207 return nil, err
196208 }
209221
210222 // ExistsP checks whether a dot notation path exists.
211223 func (g *Container) ExistsP(path string) bool {
212 return g.Exists(resolveJSONDotPathHierarchy(path)...)
224 return g.Exists(DotPathToSlice(path)...)
213225 }
214226
215227 // Index attempts to find and return an element within a JSON array by an index.
332344 // of the path that do not exist will be constructed, and if a collision occurs
333345 // with a non object type whilst iterating the path an error is returned.
334346 func (g *Container) SetP(value interface{}, path string) (*Container, error) {
335 return g.Set(value, resolveJSONDotPathHierarchy(path)...)
347 return g.Set(value, DotPathToSlice(path)...)
336348 }
337349
338350 // SetIndex attempts to set a value of an array element based on an index.
351363 // (https://tools.ietf.org/html/rfc6901) and sets the leaf to a value. Returns
352364 // an error if the pointer could not be resolved due to missing fields.
353365 func (g *Container) SetJSONPointer(value interface{}, path string) (*Container, error) {
354 hierarchy, err := resolveJSONPointerHierarchy(path)
366 hierarchy, err := JSONPointerToSlice(path)
355367 if err != nil {
356368 return nil, err
357369 }
367379 // ObjectP creates a new JSON object at a target path using dot notation.
368380 // Returns an error if the path contains a collision with a non object type.
369381 func (g *Container) ObjectP(path string) (*Container, error) {
370 return g.Object(resolveJSONDotPathHierarchy(path)...)
382 return g.Object(DotPathToSlice(path)...)
371383 }
372384
373385 // ObjectI creates a new JSON object at an array index. Returns an error if the
385397 // ArrayP creates a new JSON array at a path using dot notation. Returns an
386398 // error if the path contains a collision with a non object type.
387399 func (g *Container) ArrayP(path string) (*Container, error) {
388 return g.Array(resolveJSONDotPathHierarchy(path)...)
400 return g.Array(DotPathToSlice(path)...)
389401 }
390402
391403 // ArrayI creates a new JSON array within an array at an index. Returns an error
405417 // dot notation. Returns an error if the path contains a collision with a non
406418 // object type.
407419 func (g *Container) ArrayOfSizeP(size int, path string) (*Container, error) {
408 return g.ArrayOfSize(size, resolveJSONDotPathHierarchy(path)...)
420 return g.ArrayOfSize(size, DotPathToSlice(path)...)
409421 }
410422
411423 // ArrayOfSizeI create a new JSON array of a particular size within an array at
461473 // DeleteP deletes an element at a path using dot notation, an error is returned
462474 // if the element does not exist.
463475 func (g *Container) DeleteP(path string) error {
464 return g.Delete(resolveJSONDotPathHierarchy(path)...)
476 return g.Delete(DotPathToSlice(path)...)
465477 }
466478
467479 // MergeFn merges two objects using a provided function to resolve collisions.
566578 // notation. If the target is not a JSON array then it will be converted into
567579 // one, with its original contents set to the first element of the array.
568580 func (g *Container) ArrayAppendP(value interface{}, path string) error {
569 return g.ArrayAppend(value, resolveJSONDotPathHierarchy(path)...)
581 return g.ArrayAppend(value, DotPathToSlice(path)...)
570582 }
571583
572584 // ArrayRemove attempts to remove an element identified by an index from a JSON
591603 // ArrayRemoveP attempts to remove an element identified by an index from a JSON
592604 // array at a path using dot notation.
593605 func (g *Container) ArrayRemoveP(index int, path string) error {
594 return g.ArrayRemove(index, resolveJSONDotPathHierarchy(path)...)
606 return g.ArrayRemove(index, DotPathToSlice(path)...)
595607 }
596608
597609 // ArrayElement attempts to access an element by an index from a JSON array at a
613625 // ArrayElementP attempts to access an element by an index from a JSON array at
614626 // a path using dot notation.
615627 func (g *Container) ArrayElementP(index int, path string) (*Container, error) {
616 return g.ArrayElement(index, resolveJSONDotPathHierarchy(path)...)
628 return g.ArrayElement(index, DotPathToSlice(path)...)
617629 }
618630
619631 // ArrayCount counts the number of elements in a JSON array at a path.
627639 // ArrayCountP counts the number of elements in a JSON array at a path using dot
628640 // notation.
629641 func (g *Container) ArrayCountP(path string) (int, error) {
630 return g.ArrayCount(resolveJSONDotPathHierarchy(path)...)
642 return g.ArrayCount(DotPathToSlice(path)...)
631643 }
632644
633645 //------------------------------------------------------------------------------
761773 return &gabs, nil
762774 }
763775
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
764783 //------------------------------------------------------------------------------
16761676 }
16771677 }
16781678 }
1679
1680 func TestMarshalsJSON(t *testing.T) {
1681 sample := []byte(`{"test":{"value":10},"test2":20}`)
1682
1683 val, err := ParseJSON(sample)
1684 if err != nil {
1685 t.Fatal(err)
1686 }
1687
1688 marshaled, err := json.Marshal(val)
1689 if err != nil {
1690 t.Fatal(err)
1691 }
1692
1693 if exp, act := string(sample), string(marshaled); exp != act {
1694 t.Errorf("Unexpected result: %v != %v", act, exp)
1695 }
1696 }