JSONPatch - RFC6902

Standards Operations

Create,Add

Simple

Create a JSON document [download].

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# -*- coding:utf-8   -*-
from __future__ import absolute_import
from __future__ import print_function

from jsondata.jsondata import JSONData
from jsondata.jsonpointer import JSONPointer

# JSON in-memory document
D = JSONData(
        { 'a': { 'b': { 'c': 2, 'd': 3 } } }
    )


# the same as native Pyhton data
rdata = { 'a': { 'b': { 'c': 2, 'd': 3 } } }

# compare contained raw data by Python type
assert D.data == rdata

# compare data as JSONData object, see JSONData.__eq__
assert D == rdata

# print structure
print(D)

prints the result:

1
2
3
4
5
6
7
8
{
    "a": {
        "b": {
            "c": 2,
            "d": 3
        }
    }
}

Complex

Create a JSON document, add and create branches [download].

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# -*- coding:utf-8   -*-
from __future__ import absolute_import
from __future__ import print_function

from jsondata.jsondata import JSONData
from jsondata.jsonpointer import JSONPointer

# JSON document
jdata = { 'a': { 'b': { 'c': 2, 'd': 3 } } }

# JSON branch with array
arr = { 'e': { 'lx': [] } }

# Branch elements for array
ai0 = { 'v0': 100}
ai1 = { 'v1': 200}


# JSON branch with object
obj = { 'f': { 'ox': {} } }

# Branch elements for object
l0 = { 'o0': 10}
l1 = { 'o1': 20}


# JSON in-memory document
D = JSONData(jdata)


# Add a branch with an array
D.branch_add(JSONPointer('/a/b'),'e',arr['e'])

# Add a items to the new array
# Remark: for '-' refer to RFC6901 - array-index
D.branch_add(JSONPointer('/a/b/e/lx'),'-',ai0)
D.branch_add(JSONPointer('/a/b/e/lx'),'-',ai1)


# Add a branch with an object
D.branch_add(JSONPointer('/a/b'),'f',obj['f'])

# Add an item to the new object, from an object
D.branch_add(JSONPointer('/a/b/f/ox'),'v0',ai0['v0'])

# Add an item to the new object
ai1v1 = ai1['v1']
D.branch_add(JSONPointer('/a/b/f/ox'),'v1',ai1v1)


nodex = JSONPointer(['a','b'])(D.data)
ret = D.branch_create(nodex, ['g','x'], {})

ret['x0'] = 22
ret['x1'] = 33

ret = D.branch_create(nodex, ['g','x','xlst'], [])

ret.append('first')
ret.append('second')

rdata = {'a': {'b': {'c': 2, 'e': {'lx': [{'v0': 100},
  {'v1': 200}]},
  'd': 3, u'g': {u'x': {'x0': 22, 'x1': 33,
  u'xlst': ['first', 'second']}},
  'f': {'ox': {'v0': 100, 'v1': 200}}}}
}
assert D.data == rdata

print(D)

prints the result:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
{
    "a": {
        "b": {
            "c": 2,
            "d": 3,
            "e": {
                "lx": [
                    {
                        "v0": 100
                    },
                    {
                        "v1": 200
                    }
                ]
            },
            "f": {
                "ox": {
                    "v0": 100,
                    "v1": 200
                }
            },
            "g": {
                "x": {
                    "x0": 22,
                    "x1": 33,
                    "xlst": [
                        "first",
                        "second"
                    ]
                }
            }
        }
    }
}

Access values

Various access to values [download].

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
print D(['a', 'b', 'c'])

print D(JSONPointer('/a/b/c'))

print D('/a/b/c')

n = JSONPointer('/a/b/c')(D.data,True)
print n['c']

n = JSONPointer('/a/b/c')(D.data,True)
px = D.fetch_pointerpath(n, D.data)[0]
px.append('c')
print D(JSONPointer(px))

prints the result:

1
2
3
4
5
2
2
2
2
2

Move

Move a branch.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
target = JSONPointer('/a/b/new')
source = JSONPointer('/a/b/c')

print D(source)
n = D('/a/b')
n['c'] = 77

targetnode = target(D.data,True)
sourcenode = source(D.data,True)

D.branch_move(targetnode, 'new', sourcenode, 'c')
print D(target)

# check new position
assert D(target) == 77

# validate old position
try:
  x = D('/a/b/c')
except JSONPointerError as e:
  pass
else:
  raise

prints the result:

1
2
2
77

Remove

Remove a branch.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# get a pointer
target     = JSONPointer('/a/b/new')

# get the parent node for the pointer
targetnode = target(D.data,True)

# verify existence
x = D('/a/b/new')
assert x == 77

# remove item
D.branch_remove(targetnode, 'new')

# validate old position
try:
  x = D('/a/b/new')
except JSONPointerError as e:
  pass
else:
  raise
pass

Replace

Replace a branch.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# does not verify childnode, when 'parent=True' <=> 'new' does no longer exist
targetnode = JSONPointer('/a/b/new')(D.data,True)

# new item
sourcenode = {'alternate': 4711 }

# replace old by new item
ret = D.branch_replace(targetnode, 'f', sourcenode)
assert ret == True

# verify new item
x = D('/a/b/f/alternate')
assert x == 4711

Test

Test value.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# variant 0
ret = D.branch_test(JSONPointer('/a/b/f/alternate').get_node_value(D.data), 4711)
assert ret == True

# variant 1
ret = D.branch_test(JSONPointer('/a/b/f/alternate')(D.data), 4711)
assert ret == True

# variant 2
p = JSONPointer('/a/b/f/alternate')
ret = D.branch_test(p(D.data), 4711)
assert ret == True

Copy

Copy branch.

1
2
3
4
5
# JSON branch with array
arr = { 'cpy': { 'cx': [ 2, 3, 4, ] } }

# Copy a branch with an array
D.branch_copy(JSONPointer('/a/b'),'cpy',arr['cpy'])

Patch-Set Algebra

RFC6902 Examples

Section 3

See also

RFC6902 - section 3. Document Structure

The following is an example JSON Patch document, transferred in an

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
HTTP PATCH request:
PATCH /my/data HTTP/1.1
Host: example.org
Content-Length: 326
Content-Type: application/json-patch+json
If-Match: "abc123"
[
   {"op": "test",    "path": "/a/b/c", "value": "foo"            },
   {"op": "remove",  "path": "/a/b/c"                            },
   {"op": "add",     "path": "/a/b/c", "value": [ "foo", "bar" ] },
   {"op": "replace", "path": "/a/b/c", "value": 42               },
   {"op": "move",    "from": "/a/b/c", "path": "/a/b/d"          },
   {"op": "copy",    "from": "/a/b/d", "path": "/a/b/e"          }
]

Section 4

See also

RFC6902 - section 4. Operations

Note that the ordering of members in JSON objects is not significant; therefore, the following operation objects are equivalent:

1
2
3
{ "op": "add", "path": "/a/b/c", "value": "foo" }
{ "path": "/a/b/c", "op": "add", "value": "foo" }
{ "value": "foo", "path": "/a/b/c", "op": "add" }

Section 4.1

See also

RFC6902 - section 4.1 add

1
{ "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] }

Section 4.2

See also

RFC6902 - section 4.2 remove

1
{ "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] }

Section 4.3

See also

RFC6902 - section 4.3 replace

1
{ "op": "replace", "path": "/a/b/c", "value": 42 }

Section 4.4

See also

RFC6902 - section 4.4 move

1
{ "op": "move", "from": "/a/b/c", "path": "/a/b/d" }

Section 4.5

See also

RFC6902 - section 4.5 copy

1
{ "op": "copy", "from": "/a/b/c", "path": "/a/b/e" }

Section 4.6

See also

RFC6902 - section 4.6 test

1
{"op": "test", "path": "/a/b/c", "value": "foo" }

Section 5

See also

RFC6902 - section 5. Error Handling

1
2
3
4
[
   { "op": "replace", "path": "/a/b/c", "value": 42 },
   { "op": "test", "path": "/a/b/c", "value": "C" }
]

Appendix A.1.

See also

RFC6902 - section A.1 Adding an Object Member

An example target JSON document:

1
{ "foo": "bar"}

A JSON Patch document:

1
2
3
[
   { "op": "add", "path": "/baz", "value": "qux" }
]

The resulting JSON document:

1
2
3
4
{
   "baz": "qux",
   "foo": "bar"
}

Appendix A.2.

See also

RFC6902 - section A.2 Adding an Array Element

An example target JSON document:

1
{ "foo": [ "bar", "baz" ] }

A JSON Patch document:

1
2
3
[
   { "op": "add", "path": "/foo/1", "value": "qux" }
]

The resulting JSON document:

1
{ "foo": [ "bar", "qux", "baz" ] }

Appendix A.3.

See also

RFC6902 - section A.3 Removing an Object Member

An example target JSON document:

1
2
3
4
{
   "baz": "qux",
   "foo": "bar"
}

A JSON Patch document:

1
2
3
[
   { "op": "remove", "path": "/baz" }
]

The resulting JSON document:

1
{ "foo": "bar" }

Appendix A.4.

See also

RFC6902 - section A.4 Removing an Object Member

An example target JSON document:

1
{ "foo": [ "bar", "qux", "baz" ] }

A JSON Patch document:

1
2
3
[
   { "op": "remove", "path": "/foo/1" }
]

The resulting JSON document:

1
{ "foo": [ "bar", "baz" ] }

Appendix A.5.

See also

RFC6902 - section A.5 Replacing a Value

An example target JSON document:

1
2
3
4
{
   "baz": "qux",
   "foo": "bar"
}

A JSON Patch document:

1
2
3
[
   { "op": "replace", "path": "/baz", "value": "boo" }
]

The resulting JSON document:

1
2
3
4
{
   "baz": "boo",
   "foo": "bar"
}

Appendix A.6.

See also

RFC6902 - section A.6 5 Replacing a Value

An example target JSON document:

1
2
3
4
5
6
7
8
9
{
   "foo": {
      "bar": "baz",
      "waldo": "fred"
   },
   "qux": {
      "corge": "grault"
   }
}

A JSON Patch document:

1
2
3
[
   { "op": "move", "from": "/foo/waldo", "path": "/qux/thud" }
]

The resulting JSON document:

1
2
3
4
5
6
7
8
9
{
   "foo": {
         "bar": "baz"
   },
   "qux": {
      "corge": "grault",
      "thud": "fred"
   }
}

Appendix A.7.

See also

RFC6902 - section A.7 Moving an Array Element

An example target JSON document:

1
{ "foo": [ "all", "grass", "cows", "eat" ] }

A JSON Patch document:

1
2
3
[
   { "op": "move", "from": "/foo/1", "path": "/foo/3" }
]

The resulting JSON document:

1
{ "foo": [ "all", "cows", "eat", "grass" ] }

Appendix A.8.

See also

RFC6902 - section A.8 Testing a Value: Success

An example target JSON document:

1
2
3
4
{
   "baz": "qux",
   "foo": [ "a", 2, "c" ]
}

A JSON Patch document that will result in successful evaluation:

1
2
3
4
[
   { "op": "test", "path": "/baz", "value": "qux" },
   { "op": "test", "path": "/foo/1", "value": 2 }
]

Appendix A.9.

See also

RFC6902 - section A.9 Testing a Value: Error

An example target JSON document:

1
{ "baz": "qux" }

A JSON Patch document that will result in successful evaluation:

1
2
3
[
   { "op": "test", "path": "/baz", "value": "bar" }
]

Appendix A.10.

See also

RFC6902 - section A.10 Testing a Value: Error

An example target JSON document:

1
{ "foo": "bar" }

A JSON Patch document:

1
2
3
[
   { "op": "add", "path": "/child", "value": { "grandchild": { } } }
]

The resulting JSON document:

1
2
3
4
5
6
7
{
   "foo": "bar",
   "child": {
      "grandchild": {
      }
   }
}

Appendix A.11.

See also

RFC6902 - section A.11 0 Testing a Value: Error

An example target JSON document:

1
{ "foo": "bar" }

A JSON Patch document:

1
2
3
[
   { "op": "add", "path": "/baz", "value": "qux", "xyz": 123 }
]

The resulting JSON document:

1
2
3
4
{
   "foo": "bar",
   "baz": "qux"
}

Appendix A.12.

See also

RFC6902 - section A.12 Adding to a Nonexistent Target

An example target JSON document:

1
{ "foo": "bar" }

A JSON Patch document:

1
2
3
[
   { "op": "add", "path": "/baz/bat", "value": "qux" }
]

This JSON Patch document, applied to the target JSON document above, would result in an error (therefore, it would not be applied), because the “add” operation’s target location that references neither the root of the document, nor a member of an existing object, nor a member of an existing array.

Appendix A.13.

See also

RFC6902 - section A.13 Invalid JSON Patch Document

A JSON Patch document:

1
2
3
[
   { "op": "add", "path": "/baz", "value": "qux", "op": "remove" }
]

This JSON Patch document cannot be treated as an “add” operation, because it contains a later “op”:”remove” element. JSON requires that object member names be unique with a “SHOULD” requirement, and there is no standard error handling for duplicates.

Appendix A.14.

See also

RFC6902 - section A.14 ̃ Escape Ordering

An example target JSON document:

1
2
3
4
{
   "/": 9,
   " ̃1": 10
}

A JSON Patch document:

1
2
3
[
   {"op": "test", "path": "/ ̃01", "value": 10}
]

The resulting JSON document:

1
2
3
4
{
   "/": 9,
   " ̃1": 10
}

Appendix A.15.

See also

RFC6902 - section A.15 Comparing Strings and Numbers

An example target JSON document:

1
2
3
4
{
   "/": 9,
   " ̃1": 10
}

A JSON Patch document:

1
2
3
[
   {"op": "test", "path": "/ ̃01", "value": "10"}
]

This results in an error, because the test fails. The document value is numeric, whereas the value being tested for is a string.

Appendix A.16.

See also

RFC6902 - section A.16 Adding an Array Value

An example target JSON document:

1
{ "foo": ["bar"] }

A JSON Patch document:

1
2
3
[
   { "op": "add", "path": "/foo/-", "value": ["abc", "def"] }
]

The resulting JSON document:

1
{ "foo": ["bar", ["abc", "def"]] }