#!/usr/bin/python
#
# Takes a nested structure and flattens the nesting in to a flat python dict with the nested path
# flattened in to a single string with a dotted seperated path for the name to lookup on.
# Eg: val = { "blah" : { "foo" : { "x" : 5 } } } => ["blah.foo.x"] = 5
# Function from http://stackoverflow.com/questions/1871524/convert-from-json-to-csv-using-python
#
def FlattenJson( val, allowEmptyArrays ):
ret = {}
for i in val.keys():
if isinstance( val[i], list ):
if len(val[i]):
for j,v in enumerate(val[i]):
ret[ i + "[" + str(j) + "]" ] = v
ret = FlattenJson( ret, allowEmptyArrays )
else:
if allowEmptyArrays:
ret[i + "[0]"] = ""
elif isinstance( val[i], dict ):
get = FlattenJson( val[i], allowEmptyArrays )
for j in get.keys():
ret[ i + "." + j ] = get[j]
else:
ret[i] = val[i]
return ret
def FlattenJsonWithSimpleArray( val ):
ret = {}
for i in val.keys():
if isinstance( val[i], list ):
if len(val[i]):
for myindex in range(len(val[i])):
ret[ i + "[]" ] = val[i][myindex]
ret = FlattenJsonWithSimpleArray( ret )
else:
ret[i + "[]"] = ""
elif isinstance( val[i], dict ):
get = FlattenJsonWithSimpleArray( val[i] )
for j in get.keys():
ret[ i + "." + j ] = get[j]
else:
ret[i] = val[i]
return ret
#
# Basically the reverse of FlattenJson above
# Obj is the existing object to modify and assign to
# Path is a string of the hierachy to expand in to a python object tree to merge in to the Obj tree
# Val is the value to assign
#
def UnflattenJson( obj, path, val ):
pathList = path.split('.')
pathArray = pathList[0].split('[')
if len(pathArray) == 2:
# This is the case where it is an array, eg: sim.resources[1].cost
arrayName = pathArray[0]
arrayIndex = int(pathArray[1][:-1])
if not obj.has_key(arrayName): # Here we assume the list is inside a dict
obj[arrayName] = list()
while len(obj[arrayName]) <= arrayIndex:
# We are assuming that the list contains dicts, so arrays of values and arrays of arrays won't work
# We need to know ahead what type it is
obj[arrayName].append(dict())
if len(pathList) == 1:
obj[arrayName][arrayIndex] = val
else:
return UnflattenJson( obj[arrayName][arrayIndex], path.split('.', 1)[1], val )
else:
# Normal non-array item case
if not isinstance(obj, dict):
print ' Bad object type: ' + str(obj) + ' with path: ' + path
return False
if not obj.has_key(pathList[0]):
obj[pathList[0]] = dict()
if len(pathList) == 1:
obj[pathList[0]] = val
else:
return UnflattenJson( obj[pathList[0]], path.split('.', 1)[1], val )
return True