You could nest the dictionaries as follows:
jsondata = {}
agent={}
content={}
agent['agentid'] = 'john'
content['eventType'] = 'view'
content['othervar'] = "new"
jsondata['agent'] = agent
jsondata['content'] = content
print(json.dumps(jsondata))
Output:
Answer from C. Fennell on Stack Overflowprint {"content": {"eventType": "view", "othervar": "new"}, "agent": {"agentid": "john"}}
Creating nested Json structure with multiple key values in Python from Json - Stack Overflow
Use python to create a nested json - Stack Overflow
Build a double nested JSON object
How to Make Nested JSON Object with Python - Stack Overflow
What @andrea-f looks good to me, here another solution:
Feel free to pick in both :)
import json
dic = {
"bomber": [1, 2, 3, 4, 5],
"irritation": [1, 3, 5, 7, 8]
}
filename = "abc.pdf"
json_dict = {}
data = []
for k, v in dic.iteritems():
tmp_dict = {}
tmp_dict["keyword"] = k
tmp_dict["term_freq"] = len(v)
tmp_dict["lists"] = [{"occurrance": i} for i in v]
data.append(tmp_dict)
json_dict["filename"] = filename
json_dict["data"] = data
with open("abc.json", "w") as outfile:
json.dump(json_dict, outfile, indent=4, sort_keys=True)
It's the same idea, I first create a big json_dict to be saved directly in json. I use the with statement to save the json avoiding the catch of exception
Also, you should have a look to the doc of json.dumps() if you need future improve in your json output.
EDIT
And just for fun, if you don't like tmp var, you can do all the data for loop in a one-liner :)
json_dict["data"] = [{"keyword": k, "term_freq": len(v), "lists": [{"occurrance": i} for i in v]} for k, v in dic.iteritems()]
It could gave for final solution something not totally readable like this:
import json
json_dict = {
"filename": "abc.pdf",
"data": [{
"keyword": k,
"term_freq": len(v),
"lists": [{"occurrance": i} for i in v]
} for k, v in dic.iteritems()]
}
with open("abc.json", "w") as outfile:
json.dump(json_dict, outfile, indent=4, sort_keys=True)
EDIT 2
It looks like you don't want to save your json as the desired output, but be abble to read it.
In fact, you can also use json.dumps() in order to print your json.
with open('abc.json', 'r') as handle:
new_json_dict = json.load(handle)
print json.dumps(json_dict, indent=4, sort_keys=True)
There is still one problem here though, "filename": is printed at the end of the list because the d of data comes before the f.
To force the order, you will have to use an OrderedDict in the generation of the dict. Be careful the syntax is ugly (imo) with python 2.X
Here is the new complete solution ;)
import json
from collections import OrderedDict
dic = {
'bomber': [1, 2, 3, 4, 5],
'irritation': [1, 3, 5, 7, 8]
}
json_dict = OrderedDict([
('filename', 'abc.pdf'),
('data', [ OrderedDict([
('keyword', k),
('term_freq', len(v)),
('lists', [{'occurrance': i} for i in v])
]) for k, v in dic.iteritems()])
])
with open('abc.json', 'w') as outfile:
json.dump(json_dict, outfile)
# Now to read the orderer json file
with open('abc.json', 'r') as handle:
new_json_dict = json.load(handle, object_pairs_hook=OrderedDict)
print json.dumps(json_dict, indent=4)
Will output:
{
"filename": "abc.pdf",
"data": [
{
"keyword": "bomber",
"term_freq": 5,
"lists": [
{
"occurrance": 1
},
{
"occurrance": 2
},
{
"occurrance": 3
},
{
"occurrance": 4
},
{
"occurrance": 5
}
]
},
{
"keyword": "irritation",
"term_freq": 5,
"lists": [
{
"occurrance": 1
},
{
"occurrance": 3
},
{
"occurrance": 5
},
{
"occurrance": 7
},
{
"occurrance": 8
}
]
}
]
}
But be carefull, most of the time, it is better to save a regular .json file in order to be cross languages.
Your current code is not working because the loop iterates through the before-last item adding the }, then when the loop runs again it sets the flag to false, but the last time it ran it added a , since it thought that there will be another element.
If this is your dict: a = {"bomber":[1,2,3,4,5]} then you can do:
import json
file_name = "a_file.json"
file_name_input = "abc.pdf"
new_output = {}
new_output["filename"] = file_name_input
new_data = []
i = 0
for key, val in a.iteritems():
new_data.append({"keyword":key, "lists":[], "term_freq":len(val)})
for p in val:
new_data[i]["lists"].append({"occurrance":p})
i += 1
new_output['data'] = new_data
Then save the data by:
f = open(file_name, 'w+')
f.write(json.dumps(new_output, indent=4, sort_keys=True, default=unicode))
f.close()
Try this. Though your sample input and output data don't really give many clues as to where the "name" fields should come from. I've assumed you wanted the name of the original item in your list.
original_json = json.load(open('data/bricsinvestorsfirst.json'),'r')
response_json = {}
response_json["name"] = "analytics"
# where your children list will go
children = []
size = 500 # or whatever else you want
# For each item in your original list
for item in original_json:
children.append({"name" : item["name"],
"size" : size})
response_json["children"] = children
print json.dumps(response_json,indent=2)
"It's only outputting one entry" because you only select the first dictionary in the JSON file when you say raw_data2 = raw_data[0]
Try something like this as a starting point (I haven't tested/ran it):
import json
def run():
with open('data/bricsinvestorsfirst.json') as input_file:
raw_data = json.load(input_file)
children = []
for item in raw_data:
children.append({
'name': item['name'],
'size': '500'
})
container = {}
container['name'] = 'name'
container['children'] = children
return json.dumps(container)
if __name__ == '__main__':
print run()
This is what I want to generate to match a required file format (notice the extra level of brackets):
{
"content": [{
"eventType": "view",
"othervar": "new"
}]
}sample code:
import json
jsondata = {}
content={}
content['eventType'] = 'view'
content['othervar'] = "new"
jsondata['content'] = content
print(json.dumps(jsondata, indent=4))Current output:
{
"content": {
"eventType": "view",
"othervar": "new"
}
} EDIT: Thanks so much. I come from a long R background and am still learning the Python details.
I am a Python n00b and perhaps there is a better way to accomplish what I am trying to do but my goal is to create a multi level JSON schema and populate data dynamically via Python dictionaries.
EDIT: Added my attempted Python dictionary usage which doesn't allow me to populate data in the service_components node. The goal is to understand how to structure a Python dictionary that can be converted to the example JSON format below.
ambari_services = {'service_name':[],'service_components':[{'component_name':[],'service_name':[]}]}
ambari_services['service_name'].append('YARN')
ambari_services['service_components']['component_name']I am using the Python requests module and json module with the Hadoop Ambari REST API to pull out data for services and service components. I have manually created the below example of the JSON schema I am hoping to create and dynamically populate with data via Python.
Any help and guidance would be greatly appreciated. Thanks for reading!
{
"ambari_services": [
{
"service_name": "AMBARI_METRICS",
"service_components" : [
{
"component_name" : "METRICS_COLLECTOR",
"service_name" : "AMBARI_METRICS"
},
{
"component_name" : "METRICS_MONITOR",
"service_name" : "AMBARI_METRICS"
}
]
},
{
"service_name": "YARN",
"service_components" : [
{
"component_name" : "APP_TIMELINE_SERVER",
"service_name" : "YARN"
},
{
"component_name" : "NODEMANAGER",
"service_name" : "YARN"
},
{
"component_name" : "RESOURCEMANAGER",
"service_name" : "YARN"
},
{
"component_name" : "YARN_CLIENT",
"service_name" : "YARN"
}
]
}
]
}The rgp loop can be made more compact, and a bit faster, with:
def foo2(rgp):
alist = []
for n, g in rgp:
temp2 = {"name": n}
values = g.T.to_dict().values()
n = len(values)
def size(t):
return (t['Rating'] * t['Count'] * 10000) / n
temp3 = [{'name': t['Name'], 'size': size(t)} for t in values]
temp2['children'] = temp3
alist.append(temp2)
return alist
I don't have enough experience with Pandas to know whether it is possible to improve on the groupby. For example, it would be possible to perform a 2 level grouping with one call - ie. group on 'Count' and within that 'Rating'?
Considering that json is a string version of a dict, and you have a specific dictionary layout in mind, I don't see how you can organize the code in any other way. With the exception of update, all dictionary additions are key by key. So you have to have these 2 loops over groups.
Building on hpaulj's answer, I find if you remove temporary variables it makes the code clearer, it also makes the structure of your data much clearer. And so I'd change it to:
def foo2(rgp):
list_ = []
for name, g in rgp:
values = g.T.to_dict().values()
n = len(values)
list_.append({
'name': name,
'children': [
{
'name': t['Name'],
'size': (t['Rating'] * t['Count'] * 10000) / n
}
for t in values
]
})
return list_
You're getting error because your json file is incorrectly formatted and thus calling json.load() will raise an JSONDecodeError.
Your json structure should look like,
{
"companies": {
"company1": [
{
"path": "C:/USER/Path/Company1/",
"files": [
{
"_CO": {
"ID": "ID",
"Report Number": "Report_Number"
}
},
{
"_TR": {
"ID": "Trade_Ident",
"Report Number": "Number of Report"
}
}
]
}
],
"company2": [
{
"path": "C:/USER/Path/Company2/",
"files": [
{
"_CO": {
"ID": "Identification",
"Report Number": "Report-Number"
}
},
{
"_TR": {
"ID": "Ident",
"Report Number": "NumberReport"
}
}
]
}
]
}
}
Hope it helps you!
You have some object (the ones with curly braces) without keys, for example in
{
{"_CO": {"ID": "ID", "Report Number": "Report_Number"}}, ...
Objects in JSON are key-value pairs. Just remove the external set of braces and it should be ok.
You can use some online JSON formatter/validator just like this one, and it will easily point out the problem. Otherwise, you can use some JSON linter for your editor. It just does the work for you and also improves indentation :)