J'ai récemment commencé à travailler avec Python et j'essaie de concaténer une de mes chaînes JSON avec une chaîne JSON existante. Je travaille également avec Zookeeper, donc j'obtiens la chaîne json existante du nœud zookeeper comme je le suis) en utilisant Python bibliothèque kazoo.
# gets the data from zookeeper
data, stat = zk.get(some_znode_path)
jsonStringA = data.decode("utf-8")
si j'imprime jsonStringA
ça me donne comme ça -
{"error_1395946244342":"valueA","error_1395952003":"valueB"}
Mais si je fais print json.loads(jsonString)
alors il s'imprime comme ceci -
{u'error_1395946244342': u'valueA', u'error_1395952003': u'valueB'}
Ici, jsonStringA
aura ma chaîne JSON existante. Maintenant, j'ai une autre paire valeur/clé que je dois ajouter dans le jsonStringA
- sortant -
Ci-dessous est mon 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"
Mon jsonStringA
existant sera comme ceci après avoir extrait de zookeeper -
{"error_1395946244342":"valueA","error_1395952003":"valueB"}
Maintenant, je dois ajouter cette paire clé-valeur dans le jsonStringA
-
"timestamp_in_ms":"Error Occured on machine "+Host_info+" in datacenter "+ local_dc +" on the "+ step +" of process "+ c +"
Donc, en bref, je dois fusionner sous la paire valeur-clé -
"error_1395952167":"Error Occured on machine h1 in datacenter dc3 on the step2 of process test"
La chaîne JSON finale ressemblera donc à ceci -
{"error_1395946244342":"valueA","error_1395952003":"valueB","error_1395952167":"Error Occured on machine h1 in datacenter dc3 on the step2 of process test"}
Est-ce possible?
En supposant que a et b sont les dictionnaires que vous souhaitez fusionner:
c = {key: value for (key, value) in (a.items() + b.items())}
Pour convertir votre chaîne en dictionnaire python vous utilisez ce qui suit:
import json
my_dict = json.loads(json_str)
Mise à jour: code complet en utilisant chaînes :
# 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)
Mais je dois dire qu'en général, ce que vous essayez de faire n'est pas la meilleure pratique. Veuillez lire un peu les dictionnaires python.
Solution alternative:
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))
Et en fait, vous pouvez éviter tout cela si vous utilisez simplement un tableau pour contenir toutes vos erreurs.
Depuis Python 3.5, vous pouvez fusionner deux dict avec:
merged = {**dictA, **dictB}
( https://www.python.org/dev/peps/pep-0448/ )
Alors:
jsonMerged = {**json.loads(jsonStringA), **json.loads(jsonStringB)}
asString = json.dumps(jsonMerged)
etc.
Vous pouvez charger les deux chaînes json dans Python Dictionnaires puis les combiner. Cela ne fonctionnera que s'il y a des clés uniques dans chaque chaîne json.
import json
a = json.loads(jsonStringA)
b = json.loads(jsonStringB)
c = dict(a.items() + b.items())
# or c = dict(a, **b)
La fusion d'objets json est assez simple mais comporte quelques cas Edge lors des collisions clés. Les plus gros problèmes concernent un objet ayant une valeur de type simple et l'autre ayant un type complexe (Array ou Object). Vous devez décider de la façon dont vous voulez mettre cela en œuvre. Notre choix lorsque nous avons implémenté ceci pour json passé à chef-solo était de fusionner les objets et d'utiliser la première valeur de l'objet source dans tous les autres cas.
C'était notre solution:
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
Vous pouvez ajouter un autre cas après le premier cas pour vérifier les listes si vous souhaitez également les fusionner, ou pour des cas spécifiques lorsque des clés spéciales sont rencontrées.
Que voulez-vous dire par fusion? Les objets JSON sont une structure de données de valeur-clé. Quelle serait une clé et une valeur dans ce cas? Je pense que vous devez créer un nouveau répertoire et le remplir avec d'anciennes données:
d = {}
d["new_key"] = jsonStringA[<key_that_you_did_not_mention_here>] + \
jsonStringB["timestamp_in_ms"]
La méthode de fusion vous appartient évidemment.