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"]] }
|