import string
class JsonParser:
def __init__(self):
self.data_json = None
__list_jdt = [u'null', u'true', u'false']
def load(self, s):
print(u'[INFO] Load JSON string.')
json_type = JsonParser.__get_json_obj_type(s)
if json_type == list:
self.data_json = list()
elif json_type == dict:
self.data_json = dict()
self.__build_json_data(self.data_json, self.__parse_json_objects(s), json_type)
def dump(self):
return str(self.data_json)
def __build_json_data(self, parent, obj, typ):
if typ == dict:
count_bb = 0
count_sb = 0
obj_key = ''
obj_value = []
flg_d = True
for i in range(len(obj)):
if flg_d:
if obj[i] == ':':
flg_d = not flg_d
obj_key = obj[i - 1].replace('"', '')
else:
count_bb, count_sb = JsonParser.__cal_brackets(obj[i], count_bb, count_sb)
obj_value.append(obj[i])
if count_bb + count_sb == 0:
flg_d = not flg_d
self.__build_dict(parent, obj_key, obj_value)
obj_key = ''
obj_value = []
elif typ == list:
count_bb = 0
count_sb = 0
list_obj = []
del obj[0]
del obj[len(obj) - 1]
for i in range(len(obj)):
count_bb, count_sb = JsonParser.__cal_brackets(obj[i], count_bb, count_sb)
list_obj.append(obj[i])
if count_bb + count_sb == 0:
self.__build_list(parent, list_obj)
list_obj = []
def __build_list(self, parent, list_obj):
if list_obj[0] != ',':
if list_obj[0] == '{':
parent.append(list_obj)
parent[len(parent) - 1] = dict()
self.__build_json_data(parent[len(parent) - 1], list_obj, dict)
elif list_obj[0] == '[':
parent.append(list_obj)
parent[len(parent) - 1] = list()
self.__build_json_data(parent[len(parent) - 1], list_obj, list)
def __build_dict(self, parent, obj_key, obj_value):
if obj_value[0] == '{':
parent[obj_key] = dict()
self.__build_json_data(parent[obj_key], obj_value, dict)
elif obj_value[0] == '[':
parent[obj_key] = list()
self.__build_json_data(parent[obj_key], obj_value, list)
elif len(obj_value) == 1:
if obj_value[0] in self.__list_jdt:
if obj_value[0] == self.__list_jdt[0]:
parent[obj_key] = None
elif obj_value[0] == self.__list_jdt[1]:
parent[obj_key] = True
elif obj_value[0] == self.__list_jdt[2]:
parent[obj_key] = False
else:
raise JsonValueError(u'JSON value exception.', obj_value[0])
elif obj_value[0][0] == '"':
parent[obj_key] = obj_value[0].replace('"', '')
elif '.' in obj_value[0]:
try:
parent[obj_key] = string.atof(obj_value[0])
except ValueError:
raise JsonValueError(u'Invalid literal JSON value for float.', obj_value[0])
except:
raise JsonError(u'[ERROR] Unknown Json Error.')
else:
try:
parent[obj_key] = string.atoi(obj_value[0])
except ValueError:
raise JsonValueError(u'Invalid literal JSON value for int.', obj_value[0])
except:
raise JsonError(u'[ERROR] Unknown Json Error.')
else:
raise JsonFormatError(u'JSON format exception.')
@staticmethod
def __cal_brackets(obj, count_bb, count_sb):
if obj == '{':
count_bb += 1
if obj == '}':
count_bb -= 1
if obj == '[':
count_sb += 1
if obj == ']':
count_sb -= 1
return count_bb, count_sb
@staticmethod
def __count_quotes(s, flg):
count = 0
if flg == 0:
for cc in s:
if cc == '"':
count += 1
if flg == 1:
for cc in s:
if cc == '\'':
count += 1
return count
def __is_json_type(self, s):
if s[0] == '"':
return True
elif s in self.__list_jdt:
return True
else:
return False
def __parse_json_objects(self, str_json):
list_json = []
str_tmp = ''
for sgm_i in str_json:
if sgm_i == u'\n':
continue
if sgm_i != ' ':
if sgm_i == '{' or sgm_i == '}' or sgm_i == '[' or sgm_i == ']' or sgm_i == ':' or sgm_i == ',':
if str_tmp != '':
if str_tmp[0] == '\'' or str_tmp[len(str_tmp) - 1] == '\'':
raise JsonFormatError(
u'JSON standard does not allow single quoted strings. >>> ' + str_tmp)
if (str_tmp[0] == '"' and str_tmp[len(str_tmp) - 1] != '"') \
or (str_tmp[0] != '"' and str_tmp[len(str_tmp) - 1] == '"'):
raise JsonFormatError(u'JSON verification error, missing double quote. >>> ' + str_tmp)
elif not self.__is_json_type(str_tmp):
try:
if float(str_tmp) / 1 == float('inf') or float(str_tmp) / 1 == float('-inf'):
exit(1)
except ValueError:
print(u'[ERROR] JSON standard does not allow identifiers. >>> %s' % str_tmp)
exit(1)
except:
print(u'[ERROR] Upper limit of Python float type. >>> %s' % str_tmp)
exit(1)
if sgm_i == ':' and str_tmp[0] != '"':
raise JsonFormatError(
u'JSON standard allows only double quoted string as property key. >>> ' + str_tmp)
list_json.append(str_tmp)
str_tmp = ''
list_json.append(sgm_i)
else:
str_tmp = str_tmp + sgm_i
elif len(str_tmp) > 0 and str_tmp[0] == '"' and JsonParser.__count_quotes(str_tmp, 0) == 1:
str_tmp = str_tmp + sgm_i
return list_json
@staticmethod
def __get_json_obj_type(str_json):
for ch in str_json:
if ch == u' ':
continue
elif ch == u'[':
return list
elif ch == u'{':
return dict
else:
raise JsonInvalidKeywordError(
u'JSON standard not allow to begin with this character (root character). >>> %s', ch)
@staticmethod
def __parse_jdt(s):
if s == 'None':
return 'null'
if s == 'True':
return 'true'
if s == 'False':
return 'false'
return s
def __dict_to_json_str(self, dict_json):
str_json = str(dict_json)
list_json = []
str_tmp = ''
for sgm_i in str_json:
if sgm_i == u'\n':
continue
if sgm_i != ' ':
if sgm_i == '{' or sgm_i == '}' or sgm_i == '[' or sgm_i == ']' or sgm_i == ':' or sgm_i == ',':
if str_tmp != '':
if str_tmp[0] == '\'' or str_tmp[len(str_tmp) - 1] == '\'':
str_tmp = '"' + str_tmp[1:len(str_tmp) - 1] + '"'
if sgm_i == ':' and str_tmp[0] != '"':
raise JsonFormatError(
u'JSON standard allows only double quoted string as property key. >>> Key: ' + str_tmp)
if list_json[len(list_json) - 1] == ':':
str_tmp = self.__parse_jdt(str_tmp)
if not self.__is_json_type(str_tmp):
try:
if float(str_tmp) / 1 == float('inf') or float(str_tmp) / 1 == float('-inf'):
exit(1)
except ValueError:
print(u'[ERROR] JSON standard does not allow identifiers. >>> %s' % str_tmp)
exit(1)
except:
print(u'[ERROR] Upper limit of Python float type. >>> %s' % str_tmp)
exit(1)
list_json.append(str_tmp)
str_tmp = ''
list_json.append(sgm_i)
else:
str_tmp = str_tmp + sgm_i
elif len(str_tmp) > 0 and str_tmp[0] == '\'' and JsonParser.__count_quotes(str_tmp, 1) == 1:
str_tmp = str_tmp + sgm_i
str_tmp = ''
for sgm_j in list_json:
str_tmp += sgm_j
return str_tmp
def __deep_copy(self, obj):
if isinstance(obj, list):
return [self.__deep_copy(item) for item in obj]
elif isinstance(obj, dict):
return dict((key, self.__deep_copy(obj[key])) for key in obj)
return obj
def loadJson(self, f):
print(u'[INFO] Load the JSON file: %s' % f)
str_json = ''
file_json = open(f, 'r')
try:
while True:
line = file_json.readline()
if len(line) == 0:
break
str_json += line
except IOError:
print(u'[ERROR] IO error, please check!')
exit(1)
except:
print(u'[ERROR] Program exception!')
exit(1)
finally:
file_json.close()
self.load(str_json)
def dumpJson(self, f):
print(u'[INFO] Dump to JSON file: %s' % f)
file_json = open(f, 'w')
try:
file_json.write(self.__dict_to_json_str(self.data_json))
except IOError:
print('[ERROR] IO error, please check!')
exit(1)
finally:
file_json.close()
def loadDict(self, d):
print(u'[INFO] Load dictionary.')
str_json = str(d)
str_tgt = ''
for i in range(len(str_json)):
if str_json[i] == '\'' and str_json[i - 1] != '\\':
str_tgt += '"'
else:
str_tgt += str_json[i]
str_tgt = str_tgt.replace(': None,', ': null,').replace(': False,', ': false,').replace(': True,', ': true,')
if isinstance(d, list):
self.data_json = list()
self.__build_json_data(self.data_json, self.__parse_json_objects(str_tgt), list)
elif isinstance(d, dict):
self.data_json = dict()
self.__build_json_data(self.data_json, self.__parse_json_objects(str_tgt), dict)
def dumpDict(self):
print(u'[INFO] Return a dump object.')
return self.__deep_copy(self.data_json)
def update(self, d):
try:
self.data_json.update(d)
except ValueError:
print(u'[ERROR] Value error, please check!')
exit(1)
except:
print(u'[ERROR] Program exception!')
exit(1)
class JsonError(Exception):
def __init__(self, msg):
Exception.__init__(self, u'%s' % msg)
class JsonFormatError(JsonError):
def __init__(self, msg):
JsonError.__init__(self, u'[ERROR] %s' % msg)
class JsonValueError(JsonError):
def __init__(self, msg, var):
JsonError.__init__(self, u'[ERROR] %s >>> %s' % (msg, var))
class JsonInvalidKeywordError(JsonError):
def __init__(self, msg, kw):
JsonError.__init__(self, u'[ERROR] %s >>> %s' % (msg, kw))