JSON stands for JavaScript Object Notation, and is a convenient text file format that is useful to define structured data. As the name implies, JSON was modeled after the JavaScript syntax for the most common data types. Valid JSON files are also valid JavaScript source, and in a lot of cases, they are also Python source.
Conceptually, JSON represents data structures as combinations of mappings, sequences and atomic types such as strings and numbers. The present library is designed to manipulate these generic data structures, and not JSON per-se. Of course, the inspiration is in the JSON file format, and there is support for serialization and de-serialization to JSON. If you want, PYSON may stand for Python Structures Object Notation
That said, most functions in this library manipulate generic structures organized around mappings and sequence containers. These usually will be Python’s dicts and lists, but similar types are also supported. Optionally, more strict JSON-like rules can be enforced; e.g., in JSON, the root element must be a dictionary, dictionary keys are always (unicode) strings, and values must be strings, ints, floats, bools or NULL (the JavaScript equivalent to Python’s None).
JSON-like structures can be represented by combinations between dictionaries and lists, with simple immutable types in its nodes. Given the JSON-like structure
>>> obj = { "store": {\
... "book": [
... { "category": "reference",
... "author": "Nigel Rees",
... "title": "Sayings of the Century",
... "discount price": 8.95
... },
... { "category": "fiction",
... "author.name": "Evelyn",
... "title": "Sword of Honour",
... "price": 12.99
... }
... ]
... }
... }
Each datum can be addressed by its corresponding address. For example, the author “Nigel Rees” can be found under “store”, and is the “author” key in the first “book”. This address can be represented by a list of the key and indices used to access this information in the data structure, i.e., ['store', 'book', 0, 'author']. Additionally, these paths can be represented by strings, using the notation '$.store.book.0.author', in which $ represents the root node.
The as_path and as_str_path functions can convert between the string and list representations of these addresses
>>> as_path('$.store.book.0.author')
['store', 'book', 0, 'author']
The items can be accessed uniformly using the getitem function using the string or list notations to represent paths.
>>> getitem(obj, '$.store.book.0.author')
'Nigel Rees'
There is no requirement that the items in a path list should be strings or integers. In fact, they can be anything and it is up to the container structures to support them or not. String paths are more restrictive in which only strings and integers are allowed. This is more conformant with the JSON spec.
String keys can be enclosed by quotation marks in order to represent more complicated values, as in
>>> getitem(obj, '$.store.book.0."discount price"')
8.95
One can also test if a given node exists
>>> haspath(obj, '$.store.10."number of viewers"')
False
This standard is vaguely based on the notation defined at http://goessner.net/articles/JsonPath/.
(Probably this should go to a test module...) Converting complicated list paths to string paths
>>> as_str_path(['foo', 1, 'bar'])
u'$.foo.1.bar'
>>> as_str_path(['my root', 0, 'she said: "yeah!"'])
u'$."my root".0."she said: \\"yeah!\\""'
Return the value in a given JSON path of ‘obj’.
Parameters : | obj : JSON-like object
path : str, iterable
default :
|
---|---|
Raises : | KeyIndexError :
|
There are many different functions that, similarly to getitem, provide the write functionality to JSON structures using paths directly.
There are many similar functions that differ in the way they handle non-existing nodes and in the way they distinguish behavior in mappings and sequences structures.
The differences can be illustrated in the following example. Consider the structure
>>> obj = {'foo': [0, 1, 2]}
The most simple function that manipultes obj is updateitem. This function replaces the value of an existing path element and raises an error if the given path does not exist.
>>> updateitem(obj, '$.foo.0', 'zero'); obj
{'foo': ['zero', 1, 2]}
>>> updateitem(obj, '$.bar.0', 'zero')
Traceback (most recent call last):
...
IndexKeyError: u'$.bar.0 is empty'
A less restrictive version is the setitem function, which emulates python’s default behavior of key insertion in dictionaries and lists. It creates new keys in dictionaries, but does not try to fill up lists in any circunstance.
>>> obj = {}
>>> setitem(obj, '$.spam.ham.eggs', 'ham or spam?'); obj
{'spam': {'ham': {'eggs': 'ham or spam?'}}}
Updates obj‘s path node to given value.
Raises : | IndexKeyError :
|
---|
Updates obj‘s path node to given value. Recursively creates and updates new keys for mapping containers.
Parameters : | obj : JSON-like
path : str or list path
value : object
newmap : callable
|
---|---|
Raises : | IndexKeyError :
|
In most cases, it behaves like the __setitem__ iterface:
setitem(obj, key, value) <==> obj[key] = value.
The two optional arguments ‘fill’ and ‘fill_value’ defines how list-like sequences are handled if ‘key’ is an invalid index.
If ‘fill’ is True (default) and key == len(obj), thus indices are [0, 1, ..., len(obj) - 1], ‘value’ is appended to the end of the list. This behavior creates the new entry that is equivalent to ‘obj[key] == value’.
If ‘fill’ is True and key > len(obj), the function checks if the user had defined the ‘fill_value’ argument. The list is then filled with this value until the obj[key] is reached, and finally value is appended to the list.
Iterate over all pairs of (key, obj[key]) in obj.
If ‘obj’ is a mapping, iteritems(obj) is equivalent obj.iteritems(). If it is a sequence, iteritems(obj) behaves similarly to enumerate(obj).
See also
Examples
Supports lists and dicts
>>> list(iteritems([1,2])); list(iteritems({'foo': 'bar'}))
[(0, 1), (1, 2)]
[('foo', 'bar')]
Sequence types such as strings are also supported.
>>> list(iteritems('foo'))
[(0, 'f'), (1, 'o'), (2, 'o')]
The default behavior is to raise an error if ‘obj’ does not support indexing.
>>> iteritems(set())
Traceback (most recent call last):
...
TypeError: object of type <type 'set'> is not supported
If ‘obj’ is iterable, this behavior can be overridden by setting anyiter to True. In this case, the object is treated as a sequence.
>>> list(iteritems(set([1, 2]), anyiter=True))
[(0, 1), (1, 2)]
Iterate over all values of ‘obj’.
See also
listvalues, iteritems, obj, iterkeys
Iterate over all keys/indices of ‘obj’
See also
listkeys, iteritems, obj, itervalues
Version of iteritems that returns a list instead of an iterator.