Process branch data by 'jsondata.JSONData' 
******************************************

The module jsondata.JSONData provides for the operations on data structures,
whereas it relies for the syntax operations on 'json' and compatible compatible
packages.

The design is implemented as a container class providing high level structure 
operations and the access to the data structures by the standard by low-level 
native Python operations.
 
Provided basic operations are:

* **native access attributes**:  The node addresses for the native access to 
  the JSON in-memory representation. The data format is compatible to the 
  packages 'json' and 'jsonschema', e.g. also to 'ujson'. Thus provides
  native Python access performance.

* **branch operations**:  Handle complete sub structures as logical branches
  of a main JSON document. The interface is designed in accordance to RFC6902
  with extension for Python specifics.

* **tree utilities**: Generic tree functions for the provided in-memory
  representation by 'json' and 'jsonschema'.

Syntax Elements
===============
The current release provides the following operators for the class 'JSONPointer'.

Native JSON representation access attributes::

   attr := data, schema

Branch operations(branch_<ops>), see RFC6902::

   ops := add | copy | create | move | remove | replace
          test

Branch operators::

   ops := '[]' | '()'


Generic operations::

   ops := getTreeDiff | getPointerPath | getValueNode


Examples 
========

Examples for the provided basic calculations are:

Create,Add
----------

* **Branch Operations - create a JSON document, add and create branches**::

     import jsondata.JSONData
     import jsondata.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']).get_node(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::

    {
        "a": {
            "b": {
                "c": 2, 
                "e": {
                    "lx": [
                        {
                            "v0": 100
                        }, 
                        {
                            "v1": 200
                        }
                    ]
                }, 
                "d": 3, 
                "g": {
                    "x": {
                        "x0": 22, 
                        "x1": 33, 
                        "xlst": [
                            "first", 
                            "second"
                        ]
                    }
                }, 
                "f": {
                    "ox": {
                        "v0": 100, 
                        "v1": 200
                    }
                }
            }
        }
    }
    

Access values
-------------

* **Branch Operations - various access to values**::

    print D(['a', 'b', 'c'])

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

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

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

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

  prints the result::

    2
    2
    2
    2
    2

Move
----

* **Branch Operations - move a branch**::


    target = JSONPointer('/a/b/new')
    source = JSONPointer('/a/b/c')

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

    targetnode = target.get_node(D.data,True)
    sourcenode = source.get_node(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 JSONPointerException as e:
        pass
    else:
        raise
 
  prints the result::

    2
    77

Remove
------

* **Branch Operations - remove a branch**::

	# get a pointer
    target     = JSONPointer('/a/b/new')

	# get the parent node for the pointer
    targetnode = target.get_node(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 JSONPointerException as e:
        pass
    else:
        raise
    pass

Replace
-------

* **Branch Operations - replace a branch**::

    # does not verify childnode, when 'parent=True' <=> 'new' does no longer exist
    targetnode = JSONPointer('/a/b/new').get_node(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
----

* **Branch Operations - test value**::

    # variant 0
    ret = D.branch_test(JSONPointer('/a/b/f/alternate').get_node_or_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
----

* **Branch Operations - copy branch**::

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