jsonpointer

package module
v0.0.0-...-0480215 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 20, 2014 License: ISC Imports: 5 Imported by: 3

README

go-jsonschema

See GoDoc for documentation.

License

ISC License, See the LICENSE file for exact text.

Documentation

Overview

jsonpointer follows the IETF RFC 6901 spec for dereferenceing arbitrary values from JSON data structures. See http://tools.ietf.org/html/rfc6901 for the JSON Pointer spec.

Note that unless otherwise stated code examples are evaluated against the example data structure from http://tools.ietf.org/html/rfc6901#section-5 :

{
    "foo": ["bar", "baz"],
    "": 0,
    "a/b": 1,
    "c%d": 2,
    "e^f": 3,
    "g|h": 4,
    "i\\j": 5,
    "k\"l": 6,
    " ": 7,
    "m~n": 8
}

License

This package is licensed under the ISC License, a modernized MIT/BSD equivelent license, see: https://en.wikipedia.org/wiki/ISC_license or the LICENSE file in the source directory for further details.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ArrayIndexOutOfBounds

type ArrayIndexOutOfBounds struct {
	// contains filtered or unexported fields
}

ArrayIndexOutOfBounds errors indicate that a valid, numeric index is beyond the bounds of the array (slice) being dereferenced.

func (ArrayIndexOutOfBounds) Error

func (e ArrayIndexOutOfBounds) Error() string

Error Returns a informative error message as a string

Example

Calling Get with a pointer value that dereferences an array index beyond it's bounds will return an ArrayIndexOutOfBounds error. When calling set this also applies except that if the index is equal to the array length it is considered valid and performs ano": ["bar", "baz"], append. See above for the JSON data being evaluated.

pointer, _ := NewJSONPointerFromString("/foo/2")
_, err := pointer.Get(ExampleJson, -1)
fmt.Println(err)
Output:
array index 2 is beyond the array bounds.

type BadEscapeSequence

type BadEscapeSequence struct {
	// contains filtered or unexported fields
}

BadEscapeSequence errors indicate that the provided JSON pointer string contained an invalid escape sequence. Currenly the only allowed escape sequences are "~0" which escapes "~" and "~1" which escapes "/". The '~' character must not be followed by any character other than '0' or '1'.

func (BadEscapeSequence) Error

func (e BadEscapeSequence) Error() string

Error Returns a informative error message as a string

Example

Providing a string with an invalid escape sequence to NewJSONPointer will return a BadEscapeSequence error. See above for the JSON data being evaluated.

_, err := NewJSONPointerFromString("/foo/~2")
fmt.Print(err)
Output:
the escape sequence "~2" found in the JSON pointer "/foo/~2" is invalid

type InvalidArrayIndex

type InvalidArrayIndex struct {
	// contains filtered or unexported fields
}

InvalidArrayIndex errors indicate that the JSONPointer could not dereference an array using the given token (I.E. the token was not numberic, or '-' in the case of Set() calls.)

func (InvalidArrayIndex) Error

func (e InvalidArrayIndex) Error() string

Error Returns a informative error message as a string

Example

Calling Get or Set with a pointer value that dereferences an array index where the token is non-numeric will return an InvalidArrayIndex error. When calling Set this also applies except that the token "-" is evaluated to the length of the array (and thus performs an append.) See above for the JSON data being evaluated.

pointer, _ := NewJSONPointerFromString("/foo/!")
_, err := pointer.Get(ExampleJson, -1)
fmt.Println(err)
Output:
cannot index an array by the value "!"

type JSONPointer

type JSONPointer struct {
	// contains filtered or unexported fields
}

JSONPointer follows IETF RFC 6901 for using a string value to test, access and/or modify a JSON data structure. The zero value of a JSONPointer would be have zero tokens and a string representation of "" (the empty string.) This zero value is functionally usable and targets the root document itself.

func NewJSONPointerFromString

func NewJSONPointerFromString(pointer string) (*JSONPointer, error)

NewJSONPointer attempts to create a new JSONPointer instance from it's string representation according to IETF RFC 6901 rules. The primary use case for this would be to query a JSON data structure.

Example

This example represents the example tests outlined in setion 5 of IETF RFC 6901 (http://tools.ietf.org/html/rfc6901#section-5) which all pass:

pointer, _ := NewJSONPointerFromString("")
value, _ := pointer.Get(ExampleJson, -1)
fmt.Println(reflect.DeepEqual(value, ExampleJson))

pointer, _ = NewJSONPointerFromString("/foo")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(reflect.DeepEqual(value, ExampleJson["foo"]))

pointer, _ = NewJSONPointerFromString("/foo/0")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(reflect.DeepEqual(value, "bar"))

pointer, _ = NewJSONPointerFromString("/")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(0))

pointer, _ = NewJSONPointerFromString("/a~1b")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(1))

pointer, _ = NewJSONPointerFromString("/c%d")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(2))

pointer, _ = NewJSONPointerFromString("/e^f")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(3))

pointer, _ = NewJSONPointerFromString("/g|h")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(4))

pointer, _ = NewJSONPointerFromString("/i\\j")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(5))

pointer, _ = NewJSONPointerFromString("/k\"l")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(6))

pointer, _ = NewJSONPointerFromString("/ ")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(7))

pointer, _ = NewJSONPointerFromString("/m~0n")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(8))
Output:
true
true
true
true
true
true
true
true
true
true
true
true

func NewJSONPointerFromTokens

func NewJSONPointerFromTokens(tokens *[]string) *JSONPointer

NewJSONPointerFromTokens attempts to create a new JSONPointer instance from a slice of strings representing it's individual tokens. The primary use case for this would be to convert a sequence of tokens into an IETF RFC 6901 compliant string representation.

Example

This example represents the example tests outlined in setion 5 of IETF RFC 6901 as they would be implemented with NewJSONPointerFromTokens for comparison with the other constructor methods. Note that this method has no error conditions providing a nicer (or at least more chainable) API.

value, _ := NewJSONPointerFromTokens(&[]string{}).Get(ExampleJson, -1)
fmt.Println(reflect.DeepEqual(value, ExampleJson))

value, _ = NewJSONPointerFromTokens(&[]string{"foo"}).Get(ExampleJson, -1)
fmt.Println(reflect.DeepEqual(value, ExampleJson["foo"]))

value, _ = NewJSONPointerFromTokens(&[]string{"foo", "0"}).Get(
	ExampleJson,
	-1)
fmt.Println(reflect.DeepEqual(value, "bar"))

value, _ = NewJSONPointerFromTokens(&[]string{""}).Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(0))

value, _ = NewJSONPointerFromTokens(&[]string{"a/b"}).Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(1))

value, _ = NewJSONPointerFromTokens(&[]string{"c%d"}).Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(2))

value, _ = NewJSONPointerFromTokens(&[]string{"e^f"}).Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(3))

value, _ = NewJSONPointerFromTokens(&[]string{"g|h"}).Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(4))

value, _ = NewJSONPointerFromTokens(&[]string{"i\\j"}).Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(5))

value, _ = NewJSONPointerFromTokens(&[]string{"k\"l"}).Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(6))

value, _ = NewJSONPointerFromTokens(&[]string{" "}).Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(7))

value, _ = NewJSONPointerFromTokens(&[]string{"m~n"}).Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(8))
Output:
true
true
true
true
true
true
true
true
true
true
true
true

func NewJSONPointerFromURIFragment

func NewJSONPointerFromURIFragment(fragment string) (*JSONPointer, error)

NewJSONPointerFromURIFragment works just like NewJSONPointerFromString except that it will unescape URL escape sequences (like %20 for a space). A leading '#' fragment root token is optional in light of the fact that it is stripped from net/url standard library Url struct "Fragment" fields.

Example

This example represents the example tests outlined in setion 6 of IETF RFC 6901 (http://tools.ietf.org/html/rfc6901#section-6) which all pass.

pointer, _ := NewJSONPointerFromURIFragment("#")
value, _ := pointer.Get(ExampleJson, -1)
fmt.Println(reflect.DeepEqual(value, ExampleJson))

pointer, _ = NewJSONPointerFromURIFragment("#/foo")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(reflect.DeepEqual(value, ExampleJson["foo"]))

pointer, _ = NewJSONPointerFromURIFragment("#/foo/0")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(reflect.DeepEqual(value, "bar"))

pointer, _ = NewJSONPointerFromURIFragment("#/")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(0))

pointer, _ = NewJSONPointerFromURIFragment("#/a~1b")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(1))

pointer, _ = NewJSONPointerFromURIFragment("#/c%25d")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(2))

pointer, _ = NewJSONPointerFromURIFragment("#/e%5Ef")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(3))

pointer, _ = NewJSONPointerFromURIFragment("#/g%7Ch")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(4))

pointer, _ = NewJSONPointerFromURIFragment("#/i%5Cj")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(5))

pointer, _ = NewJSONPointerFromURIFragment("#/k%22l")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(6))

pointer, _ = NewJSONPointerFromURIFragment("#/%20")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(7))

pointer, _ = NewJSONPointerFromURIFragment("#/m~0n")
value, _ = pointer.Get(ExampleJson, -1)
fmt.Println(value.(float64) == float64(8))
Output:
true
true
true
true
true
true
true
true
true
true
true
true

func (*JSONPointer) Depth

func (p *JSONPointer) Depth() int

Depth returns the number of tokens in a JSON Pointer.

Example

Note that the first example is a JSON pointer to the root document, while the second example references the empty string key ("") directly under the root document.

pointer, _ := NewJSONPointerFromString("")
fmt.Println(pointer.Depth())

pointer, _ = NewJSONPointerFromString("/")
fmt.Println(pointer.Depth())

pointer, _ = NewJSONPointerFromString("/foo")
fmt.Println(pointer.Depth())

pointer, _ = NewJSONPointerFromString("/foo/bar/baz")
fmt.Println(pointer.Depth())
Output:
0
1
1
3

func (*JSONPointer) Get

func (p *JSONPointer) Get(data interface{}, depth int) (interface{}, error)

Get returns the value from the provided JSON data structure identified by this JSONPointer. The `depth` argument can be used to limit the number of tokens that will be evaluated into the structure, a value of -1 will evaluate the entire token chain, a value of 0 will return the provided data structure itself.

Example
pointer, err := NewJSONPointerFromString("/foo")
value, err := pointer.Get(ExampleJson, -1)
fmt.Println(value, err)

pointer, err = NewJSONPointerFromString("/foo/0")
value, err = pointer.Get(ExampleJson, -1)
fmt.Println(value, err)

pointer, err = NewJSONPointerFromString("/foo/0/boom")
value, err = pointer.Get(ExampleJson, -1)
fmt.Println(value, err)

pointer, err = NewJSONPointerFromString("/foo/0/boom")
value, err = pointer.Get(ExampleJson, 2)
fmt.Println(value, err)
Output:
[bar baz] <nil>
bar <nil>
<nil> cannot index primitave value "bar"
bar <nil>

func (*JSONPointer) Set

func (p *JSONPointer) Set(data interface{}, value interface{}, depth int) (interface{}, error)

Set changes the value from the provided JSON data structure identified by this JSONPointer. The `depth` argument can be used to limit the number of tokens that will be evaluated into the structure, a value of -1 will evaluate the entire token chain, a value of 0 will return the provided data structure itself. Set always returns the provided data structure, this way if an append occurs on the root level document you will receive the updated array which may have been reallocated by Go.

Example
// Construct the same JSON data structure used by other examples, but since
// it will be modified we create a new instance that won't effect other
// tests.
var Json map[string]interface{}
_ = json.Unmarshal([]byte(JSONBytes), &Json)

pointer, _ := NewJSONPointerFromString("/foo/2")
value, _ := pointer.Set(Json, "qux", -1)
value, err := pointer.Get(value, 1)
fmt.Println(value, err)

// Lets see what happens with an array index greater than the length
pointer, _ = NewJSONPointerFromString("/foo/4")
_, err = pointer.Set(Json, "corge", -1)
fmt.Println(err)

// The '-' token is a special token that can only be used for Set operations
// which will always append to the end of an array.
pointer, _ = NewJSONPointerFromString("/foo/-")
_, err = pointer.Set(Json, "corge", -1)
value, _ = pointer.Get(Json, 1)
fmt.Println(value)

// Oops, that's the wrong metastatic variable!
pointer, _ = NewJSONPointerFromString("/foo/3")
_, err = pointer.Set(Json, "quux", -1)
value, _ = pointer.Get(Json, 1)
fmt.Println(value)

pointer, _ = NewJSONPointerFromString("/o@p")
_, _ = pointer.Set(Json, 9, -1)
value, err = pointer.Get(Json, -1)
fmt.Println(value)

// Finally let's engineer a situation where an append must occur on the root
// document to illustrate that in this corner case you will only see the
// changed data if you capture the returned data:
data := make([]interface{}, 2, 2)
data[0], data[1] = "bar", "baz"
pointer, _ = NewJSONPointerFromString("/2")
value, _ = pointer.Set(data, "qux", -1)
fmt.Println(data, value)
Output:
[bar baz qux] <nil>
array index 4 is beyond the array bounds.
[bar baz qux corge]
[bar baz qux quux]
9
[bar baz] [bar baz qux]

func (*JSONPointer) String

func (p *JSONPointer) String() string

String returns the unescaped IETF RFC 6901 string representation of this JSON pointer.

Example

One of the likely use cases for constructing JSONPointers from string slices as is done with NewJSONPointerFromTokens would be to construct a valid JSONPointer string for a given property/index path. Here's how to do that:

pointer := NewJSONPointerFromTokens(&[]string{})
fmt.Printf("%q\n", pointer.String())

pointer = NewJSONPointerFromTokens(&[]string{""})
fmt.Printf("%q\n", pointer.String())

pointer = NewJSONPointerFromTokens(&[]string{"foo"})
fmt.Printf("%q\n", pointer.String())

pointer = NewJSONPointerFromTokens(&[]string{"foo", "bar", "baz"})
fmt.Printf("%q\n", pointer.String())
Output:
""
"/"
"/foo"
"/foo/bar/baz"

func (*JSONPointer) Tokens

func (p *JSONPointer) Tokens() []string

Tokens returns the escaped tokens that will be used to dereference a JSON data structure.

Example

Note that the difference between the first and second example is that the first is completely empty, while the second contains one string which happens to be the empty string ("".)

pointer, _ := NewJSONPointerFromString("")
tokens := pointer.Tokens()
fmt.Println(len(tokens), tokens)

pointer, _ = NewJSONPointerFromString("/")
tokens = pointer.Tokens()
fmt.Println(len(tokens), tokens)

pointer, _ = NewJSONPointerFromString("/foo")
tokens = pointer.Tokens()
fmt.Println(len(tokens), tokens)

pointer, _ = NewJSONPointerFromString("/foo/bar/baz")
tokens = pointer.Tokens()
fmt.Println(len(tokens), tokens)
Output:
0 []
1 []
1 [foo]
3 [foo bar baz]

type JSONPointerSyntaxError

type JSONPointerSyntaxError struct {
	// contains filtered or unexported fields
}

JSONPointerSyntaxError indicates that the provided string representation of a JSON pointer is invalid. To be a valid JSON pointer string it must either: be the empty string (""), or start with a forward slash ("/").

func (JSONPointerSyntaxError) Error

func (e JSONPointerSyntaxError) Error() string

Error Returns a informative error message as a string

Example

Calling NewJSONPointerFromString with a string that neither is the empty string nor starts with a "/" is invalid and will return a JSONPointerSyntaxError

_, err := NewJSONPointerFromString("boom")
fmt.Print(err)
Output:
"boom" is not a valid JSON pointer string representation.

type UnindexableValue

type UnindexableValue struct {
	// contains filtered or unexported fields
}

UnindexableValue error indicates that the JSONPointer reached a primitave value which cannot be indexed into before running out of tokens to dereference.

func (UnindexableValue) Error

func (e UnindexableValue) Error() string

Error Returns a informative error message as a string

Example

Calling Get or Set with a pointer that dereferences a primitave (null/nil, boolean/bool, number/float64 or string) before exausting all tokens to be evaluated will return a UnindexableValue error. See above for the JSON data being evaluated.

pointer, _ := NewJSONPointerFromString("/foo/0/boom/big")
_, err := pointer.Set(ExampleJson, "badda", -1)
fmt.Println(err)
Output:
cannot index primitave value "bar"

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL