如何在 Python 中合并两个 json 字符串?

Posted

技术标签:

【中文标题】如何在 Python 中合并两个 json 字符串?【英文标题】:How to merge two json string in Python? 【发布时间】:2014-05-07 01:17:32 【问题描述】:

我最近开始使用 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"

我现有的jsonStringA从zookeeper提取后会是这个样子-

"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"

这可能吗?

【问题讨论】:

【参考方案1】:

假设 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))

如果你只使用一个数组来保存所有错误,实际上你可以避免所有这些。

【讨论】:

您使用字符串还是字典?我给你的例子是正确的。 我再次更新了问题。因为我最近开始使用 Python,所以不确定字典在这里是什么意思。我也更新了我的jsonStringA 如何打印出来的问题。我想我需要附加的字符串是一个简单的字符串。 我更新了我的答案。现在我使用纯 json 字符串作为输入。请仔细阅读,以便您了解字符串和字典发生的情况。 现在说得通了.. 最后一个问题我如何正确地制作 jsonStringB 的所有值?因为我需要用变量中的所有值创建一个键值对。 另外,请注意,这将通过用b 中的值覆盖a 中的值来静默处理键冲突。【参考方案2】:

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

等等

【讨论】:

如果有嵌套字典,这不起作用 请注意,字典解包会消耗大量资源 请注意,这将通过用 dictB 中的值覆盖 dictA 中的值来静默处理键冲突。【参考方案3】:

您可以将两个 json 字符串加载到 Python 字典中,然后合并。这只有在每个 json 字符串中都有唯一的键时才有效。

import json

a = json.loads(jsonStringA)
b = json.loads(jsonStringB)
c = dict(a.items() + b.items())
# or c =  dict(a, **b)

【讨论】:

请不要使用dict(a, **b)。这实际上是对CPython 实现的滥用。而是使用c = a.copy(); c.update(b)【参考方案4】:

合并 json 对象相当简单,但在处理键冲突时会出现一些边缘情况。最大的问题与一个对象具有简单类型的值而另一个对象具有复杂类型(数组或对象)有关。您必须决定如何实现它。当我们为传递给 chef-solo 的 json 实现这一点时,我们的选择是合并对象并在所有其他情况下使用第一个源对象的值。

这是我们的解决方案:

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 字符串都有 key:value 对,它们都是字符串。我没有任何数组的东西.. 那么别担心,这段代码在这种情况下可以正常工作。 最后一个问题,在我的情况下,如何将 json_string2 作为键值对?因为我需要从我拥有的变量构造这个 json 字符串。有什么想法吗? 啊,我想我看错了你的代码,我相信你的 jsonString[AB] 实际上是我的代码的 json_string[12]。我将编辑我的代码以反映该假设。【参考方案5】:

要将键值对附加到 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

【讨论】:

【参考方案6】:

合并是什么意思? JSON 对象是键值数据结构。在这种情况下,键和值是什么?我认为您需要创建新目录并用旧数据填充它:

d = 
d["new_key"] = jsonStringA[<key_that_you_did_not_mention_here>] + \ 
               jsonStringB["timestamp_in_ms"]

合并方法显然取决于你。

【讨论】:

以上是关于如何在 Python 中合并两个 json 字符串?的主要内容,如果未能解决你的问题,请参考以下文章

在python中合并两个json文件

将两个json文件合并为一个文件Python

合并具有相同属性值的json对象c#

如何使用 Python 合并或使用字符串连接两个熊猫数据框

python3两个字典的合并

将两个json数组合并为一个