Basic JSON structures — pyson v0.1.2 documentation

### Navigation

- index
- modules |
- modules |
- next |
- previous |
- pyson v0.1.2 documentation »

# Basic JSON structures

JSON stands for JavaScript Object Notation, is a lightweight file format used to define structured data. As the name implies, JSON was modeled after the JavaScript syntax and it represents its most common data types. A valid JSON file is also a valid JavaScript source, and in a lot of cases, it is also a valid 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 data per-se. Of course, the inspiration is in the JSON file format, and there is support for serialization and de-serialization to/from 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 Paths

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

### Notes

This standard is vaguely based on the notation defined at http://goessner.net/articles/JsonPath/.

### Doctests

(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!\\""'

### API Documentation

`getitem`(obj, path, default=DEFAULT)

  Return the value in a given JSON path of ‘obj’.

  Parameters : | obj : JSON-like object JSON structure (list-like or dictionary-like) path : str, iterable The path can be a string of the form `"$.child.toys.0"` or an iterable that expands to `['child', 'toys', 0]` default : Return this value if obj does possess the desired path node.
  Raises : | KeyIndexError : If path is not present in `obj’.

`haspath`(obj, path)

  Return True if `obj` has a value associated with the given `path`.

`as_path`(path)

  Convert a string that represents a JSON path into a tuple.

`as_str_path`(path)

  Represents a given ‘path’ as a valid query string

## Setting values

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?'}}}

### API Documentation

`updateitem`(obj, path, value)

  Updates `obj`‘s `path` node to given `value`.

  Raises : | IndexKeyError : If the node is empty.

`setitem`(obj, path, value, newmap=None)

  Updates `obj`‘s `path` node to given `value`. Recursively creates and updates new keys for mapping containers.

  Parameters : | obj : JSON-like JSON-like structure. path : str or list path Any valid JSON path. value : object Any value to be assigned to the given path node. newmap : callable Factory function for creating new mappings. By default it tries to use the same type as the innermost dictionary. This function, called with no arguments, should return a new dictionary-like object.
  Raises : | IndexKeyError : If a node in a sequence container is empty.

`writeitem`(obj, path, value, newmap=None, newseq=None, newitem=None)

  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.

`iteritems`(obj, anyiter=False)

  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

  `listitems`, `iterkeys`, `itervalues`

  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)]

`itervalues`(obj, anyiter=False)

  Iterate over all values of ‘obj’.

  See also

  `listvalues`, `iteritems`, `obj`, `iterkeys`

`iterkeys`(obj, anyiter=False)

  Iterate over all keys/indices of ‘obj’

  See also

  `listkeys`, `iteritems`, `obj`, `itervalues`

`listitems`(obj, anyiter=False)

  Version of iteritems that returns a list instead of an iterator.

`listvalues`(obj, anyiter=False)

  Version of itervalues that returns a list instead of an iterator.

`listkeys`(obj, anyiter=False)

  Version of iterkeys that returns a list instead of an iterator.

### Navigation

- index
- modules |
- modules |
- next |
- previous |
- pyson v0.1.2 documentation »