如何在Python中合并两个json字符串?
我最近开始学习Python,现在想把一个JSON字符串和已有的JSON字符串拼接在一起。我还在使用Zookeeper,所以我通过Python的kazoo库从Zookeeper节点获取现有的JSON字符串。
# gets the data from zookeeper
data, stat = zk.get(some_znode_path)
jsonStringA = data.decode("utf-8")
如果我打印jsonStringA
,它会显示成这样 -
{"error_1395946244342":"valueA","error_1395952003":"valueB"}
但是如果我执行print json.loads(jsonString)
,它会显示成这样 -
{u'error_1395946244342': u'valueA', u'error_1395952003': u'valueB'}
这里的jsonStringA
就是我已有的JSON字符串。现在我有一个新的键值对需要添加到这个jsonStringA
中 -
下面是我的Python代码 -
# gets the data from zookeeper
data, stat = zk.get(some_znode_path)
jsonStringA = data.decode("utf-8")
timestamp_in_ms = "error_"+str(int(round(time.time() * 1000)))
node = "/pp/tf/test/v1"
a,b,c,d = node.split("/")[1:]
host_info = "h1"
local_dc = "dc3"
step = "step2"
从Zookeeper提取后,我的现有jsonStringA
会是这样的 -
{"error_1395946244342":"valueA","error_1395952003":"valueB"}
现在我需要把这个键值对添加到jsonStringA
中 -
"timestamp_in_ms":"Error Occured on machine "+host_info+" in datacenter "+ local_dc +" on the "+ step +" of process "+ c +"
简单来说,我需要合并下面的键值对 -
"error_1395952167":"Error Occured on machine h1 in datacenter dc3 on the step2 of process test"
最终的JSON字符串会是这样的 -
{"error_1395946244342":"valueA","error_1395952003":"valueB","error_1395952167":"Error Occured on machine h1 in datacenter dc3 on the step2 of process test"}
这样做可以吗?
6 个回答
要把键值对添加到一个json字符串里,你可以使用 dict.update 方法: dictA.update(dictB)
。
在你的情况下,代码会像这样:
dictA = json.loads(jsonStringA)
dictB = json.loads('{"error_1395952167":"Error Occured on machine h1 in datacenter dc3 on the step2 of process test"}')
dictA.update(dictB)
jsonStringA = json.dumps(dictA)
需要注意的是,如果两个字典里有相同的键,dictB
的值会覆盖掉 dictA
里的值。
合并 JSON 对象其实挺简单的,但在处理键冲突时会有一些特殊情况。最大的麻烦在于,一个对象的值是简单类型,而另一个对象的值是复杂类型(比如数组或对象)。这时候你需要决定怎么处理这种情况。我们在为 chef-solo 实现这个功能时,选择了合并对象,并在其他情况下使用第一个源对象的值。
这是我们的解决方案:
from collections import Mapping
import json
original = json.loads(jsonStringA)
addition = json.loads(jsonStringB)
for key, value in addition.iteritems():
if key in original:
original_value = original[key]
if isinstance(value, Mapping) and isinstance(original_value, Mapping):
merge_dicts(original_value, value)
elif not (isinstance(value, Mapping) or
isinstance(original_value, Mapping)):
original[key] = value
else:
raise ValueError('Attempting to merge {} with value {}'.format(
key, original_value))
else:
original[key] = value
如果你想合并列表,也可以在第一个情况后面再加一个判断,或者在遇到特殊键时处理特定情况。
你可以把两个json字符串加载到Python字典里,然后把它们合并在一起。不过,这样做的前提是每个json字符串里的键必须是唯一的,也就是说不能有重复的键。
import json
a = json.loads(jsonStringA)
b = json.loads(jsonStringB)
c = dict(a.items() + b.items())
# or c = dict(a, **b)
从Python 3.5开始,你可以用以下方法合并两个字典:
merged = {**dictA, **dictB}
(https://www.python.org/dev/peps/pep-0448/)
所以:
jsonMerged = {**json.loads(jsonStringA), **json.loads(jsonStringB)}
asString = json.dumps(jsonMerged)
等等。
假设a和b是你想要合并的字典:
c = {key: value for (key, value) in (a.items() + b.items())}
要把你的字符串转换成Python字典,可以使用以下方法:
import json
my_dict = json.loads(json_str)
更新:使用字符串的完整代码:
# test cases for jsonStringA and jsonStringB according to your data input
jsonStringA = '{"error_1395946244342":"valueA","error_1395952003":"valueB"}'
jsonStringB = '{"error_%d":"Error Occured on machine %s in datacenter %s on the %s of process %s"}' % (timestamp_number, host_info, local_dc, step, c)
# now we have two json STRINGS
import json
dictA = json.loads(jsonStringA)
dictB = json.loads(jsonStringB)
merged_dict = {key: value for (key, value) in (dictA.items() + dictB.items())}
# string dump of the merged dict
jsonString_merged = json.dumps(merged_dict)
不过我得说,通常你想做的事情并不是最佳做法。建议你多了解一下Python字典的相关知识。
替代方案:
jsonStringA = get_my_value_as_string_from_somewhere()
errors_dict = json.loads(jsonStringA)
new_error_str = "Error Ocurred in datacenter %s blah for step %s blah" % (datacenter, step)
new_error_key = "error_%d" % (timestamp_number)
errors_dict[new_error_key] = new_error_str
# and if I want to export it somewhere I use the following
write_my_dict_to_a_file_as_string(json.dumps(errors_dict))
其实,如果你直接用一个数组来存放所有的错误,就可以避免这些问题。