Add json data recursively to json object python - python

I have this initial json which I made in this piece of code:
menu_structure = []
menu_root = cursor.fetchall()
for menu_item in menu_root:
menu_structure.append({"name": menu_item[1]})
get_tree_branch(lang=lang, id_parent=menu_item[0], parent_name=menu_item[1], menu_structure=menu_structure,
cursor=cursor)
JSON 1
[
{
"name": "Fish",
"children": [
{
"name": "Fish of two waters"
},
{
"name": "Sea water fish"
},
{
"name": "Fresh water fish"
}
]
},
{
"name": "Seafood"
}
]
I made a sql petition to see if Fish of two waters has a children, if it has a children then I only receive a string with the name of children and I want to add the children to the json object like this:
JSON 2
[
{
"name": "Fish",
"children": [
{
"name": "Fish of two waters",
"children": [
{
"name": "Test fish"
}]
},
{
"name": "Sea water fish"
},
{
"name": "Fresh water fish"
}
]
},
{
"name": "Seafood"
}
]
To do that in my python code I do this:
def get_tree_branch(lang: str, id_parent: int, menu_structure, cursor):
sql_query = "select ps_category.id_category, name from ps_category Right Join ps_category_lang On " \
"ps_category.id_category = ps_category_lang.id_category Right Join ps_lang on " \
"ps_category_lang.id_lang = ps_lang.id_lang where ps_category.is_root_category = 0 " \
"AND ps_category.id_parent like %s AND ps_lang.lang_name = %s"
sql_params = (id_parent, lang)
cursor.execute(query=sql_query, args=sql_params)
menu_branch = cursor.fetchall()
if menu_branch:
menu_structure[len(menu_structure) - 1]["children"] = []
for menu_item in menu_branch:
menu_structure[len(menu_structure) - 1]["children"].append({"name": menu_item[1]})
get_tree_branch(lang=lang, id_parent=menu_item[0], menu_structure=menu_structure, cursor=cursor)
else:
return
But that code instead does this json:
JSON 3
[
{
"name": "Fish",
"children": [
{
"name": "Test fish"
},
{
"name": "Sea water fish"
},
{
"name": "Fresh water fish"
}
]
},
{
"name": "Seafood"
}
]
Any suggestions on how to create a json object like the JSON 2?

For those interested I did this, hope it helps
def get_tree_menu(lang: int):
test_db = init_database()
cursor = test_db.cursor()
menu_structure = []
sql_query = """select c.id_category, cl.name from ps_category_lang as cl
left join ps_category c on cl.id_category = c.id_category
where c.is_root_category = 1 AND cl.id_lang = %s AND c.active = 1
order by c.position asc"""
cursor.execute(query=sql_query, args=lang)
menu_root = cursor.fetchall()
id_category = 0
name = 1
for menu_item in menu_root:
menu_structure.append({"name": menu_item[name]})
get_tree_branch(lang=lang, id_parent=menu_item[id_category], parent_name=menu_item[name],
menu_structure=menu_structure, cursor=cursor)
cursor.close()
close_database(test_db=test_db)
return menu_structure
def get_tree_branch(lang: int, id_parent: int, parent_name: str, menu_structure, cursor):
sql_query = """select c.id_category, cl.name from ps_category_lang as cl
left join ps_category c on cl.id_category = c.id_category
where c.is_root_category = 0 AND c.id_parent = %s AND cl.id_lang = %s AND c.active = 1
order by c.position asc"""
sql_params = (id_parent, lang)
cursor.execute(query=sql_query, args=sql_params)
menu_branch = cursor.fetchall()
id_category = 0
name = 1
if menu_branch:
for menu_item in menu_branch:
menu_structure = create_json_structure(json_object=menu_structure, search_value=parent_name,
child_name=menu_item[name])
get_tree_branch(lang=lang, id_parent=menu_item[id_category], parent_name=menu_item[name],
menu_structure=menu_structure, cursor=cursor)
else:
return
def create_json_structure(json_object: any, search_value: str, child_name: str):
"""Recursively search for values of key in JSON tree and add a child to the JSON element."""
if isinstance(json_object, dict):
for key, value in json_object.items():
if isinstance(value, (dict, list)):
create_json_structure(json_object=value, search_value=search_value, child_name=child_name)
else:
if value == search_value:
try:
json_object["children"].append({
"parentName": search_value,
"name": child_name
})
except KeyError:
json_object["children"] = []
json_object["children"].append({
"parentName": search_value,
"name": child_name
})
break
elif isinstance(json_object, list):
for item in json_object:
create_json_structure(json_object=item, search_value=search_value, child_name=child_name)
return json_object

Related

How can I iterate through a dictionary and use context managers in Python?

The dictionary I am trying to iterate through has the following structure:
d = {
"main_key_1": {
"name": "Name1",
"context": "Context1",
"message": "Message1",
"date": "Date1",
"reference": "Reference1"
},
"main_key_2": {
"name": "Name2",
"context": "Context2",
"message": "Message2",
"date": "Date2",
"reference": "Reference2"
}
}
This is the way I tried to iterate:
for item in d.items():
from_context = f"from {item[1]['context']}"
with context('given a descriptor'):
with context(from_context):
with before.all:
self.descriptor = item[1]['message']
with context('that contains a date'):
with it('recognizes the date'):
adapter = MessageToDatetAdapter(self.descriptor)
result = adapter.is_a_date()
expect(result).to(equal(True))
with it('extracts the date data'):
adapter = MessageToDatetAdapter(self.descriptor)
result = adapter.adapt()
expect(result['date']).to(equal(item[1]['date']))
expect(result['reference']).to(item[1]['reference'])
The first iteration would be something like below:
with context('given a descriptor'):
with context('from Context1'):
with before.all:
self.descriptor = 'Message1'
with context('that contains a date'):
with it('recognizes the date'):
adapter = MessageToDatetAdapter(self.descriptor)
result = adapter.is_a_date()
expect(result).to(equal(True))
with it('extracts the date data'):
adapter = MessageToDatetAdapter(self.descriptor)
result = adapter.adapt()
expect(result['date']).to('Date1')
expect(result['reference']).to('Reference1')
However, it seems like this is not correct. It looks like I cannot iterate through all the dictionary items.

How to fix the output for converting to JSON

I wrote a code in python that converts a file with these objects to JSON. It converts into the proper json format but the output is not exactly what I need.
{
name: (sindey, crosby)
game: "Hockey"
type: athlete
},
{
name: (wayne, gretzky)
game: "Ice Hockey"
type: athlete
}
Code:
import json
f = open("log.file", "r")
content = f.read()
splitcontent = content.splitlines()
d = []
for line in splitcontent:
appendage = {}
if ('}' in line) or ('{' in line):
# Append a just-created record and start a new one
continue
d.append(appendage)
key, val = line.split(':')
if val.endswith(','):
# strip a trailing comma
val = val[:-1]
appendage[key] = val
with open("json_log.json", 'w') as file:
file.write((json.dumps(d, indent=4, sort_keys=False)))
Desired output:
[
{
"name": "(sindey, crosby)",
"game": "Hockey",
"type": "athlete"
},
{
"name": "(wayne, gretzky)",
"game": "Ice Hockey",
"type": "athlete"
}
]
But I'm getting:
[
{
" name": " (sindey, crosby)"
},
{
" game": " \"Hockey\""
},
{
" type": " athlete"
},
{
" name": " (wayne, gretzky)"
},
{
" game": " \"Ice Hockey\""
},
{
" type": " athlete"
}
]
Any way to fix it to get the desired output and fix the {} around each individual line?
It's usually a good idea to split parsing into simpler tasks, e.g. first parse records, then parse fields.
I'm skipping the file handling and using a text variable:
intxt = """
{
name: (sindey, crosby)
game: "Hockey"
type: athlete
},
{
name: (wayne, gretzky)
game: "Ice Hockey"
type: athlete
}
"""
Then create a function that can yield all lines that are part of a record:
import json
def parse_records(txt):
reclines = []
for line in txt.split('\n'):
if ':' not in line:
if reclines:
yield reclines
reclines = []
else:
reclines.append(line)
and a function that takes those lines and parses each key/value pair:
def parse_fields(reclines):
res = {}
for line in reclines:
key, val = line.strip().rstrip(',').split(':', 1)
res[key.strip()] = val.strip()
return res
the main function becomes trivial:
res = []
for rec in parse_records(intxt):
res.append(parse_fields(rec))
print(json.dumps(res, indent=4))
the output, as desired:
[
{
"name": "(sindey, crosby)",
"game": "\"Hockey\"",
"type": "athlete"
},
{
"name": "(wayne, gretzky)",
"game": "\"Ice Hockey\"",
"type": "athlete"
}
]
The parsing functions can of course be made better, but you get the idea.
Yes I haven't checked the ouput properly, I remodified the logic now. The output is as expected.
import json
f = open("log.file", "r")
content = f.read()
print(content)
splitcontent = content.splitlines()
d = []
for line in splitcontent:
if "{" in line:
appendage = {}
elif "}" in line:
d.append(appendage)
else:
key, val = line.split(':')
appendage[key.strip()] = val.strip()
with open("json_log.json", 'w') as file:
file.write((json.dumps(d, indent=4, sort_keys=False)))

return data from json file if another one is not exist

I'm trying to return data to Django model, from Overpass API JSON data after downloaded
"elements": [
{
"type": "node",
"id": 662934404,
"lat": 35.572157,
"lon": 45.3898839,
"tags": {
"addr:postcode": "46001",
"name": "City Center",
"name:en": "City Center Mall",
"name:ku": "City Center Mall",
"shop": "mall",
"website": "http://www.citycentersul.com"
}
},
{
"type": "node",
"id": 2413990402,
"lat": 35.5014386,
"lon": 45.4457576,
"tags": {
"addr:city": "sulaymaniyah",
"designation": "ASSAN",
"name": "ASSAN STEEL CO.",
"opening_hours": "3 min",
"shop": "doityourself",
"source": "ASSAN Steel Company General Trading Co, Ltd"
},
{
"type": "node",
"id": 2414374708,
"lat": 35.506121,
"lon": 45.4417229,
"tags": {
"addr:city": "sulaymaniyah",
"name:ku": "ASSAN Steel Company General Trading Co, Ltd",
"shop": "doityourself",
}
},
but some of the data dosent have both of them together name , name:ku ,name:en
so what should i do if name is none then return name:ku , if its exists then name:en
i've tried this but doesnt work
with open('data.json') as datafile:
objects = json.load(datafile)
for obj in objects['elements']:
try:
objType = obj['type']
if objType == 'node':
tags = obj['tags']
name = tags.get('name')
if not name:
name = tags.get('name:en')
elif not name:
name = tags.get('name:ku')
elif not name:
name = tags.get('name:ar')
else:
name = tags.get('shop','no-name')
is there something else I've missed?
thanks for helping
You could loop over all possible keys and stop after a value was detected:
with open('data.json') as datafile:
objects = json.load(datafile)
for obj in objects['elements']:
objType = obj['type']
if objType == 'node':
tags = obj['tags']
name = None
for nameId in ('name', 'name:en', 'name:ku', 'name:ar'):
if nameId in tags:
name = tags[name]
break # stop looping, we got a name value
# Set default if no key was found
if not name:
name = tags.get('shop','no-name')
The following and all subsequent elif-conditions are wrong:
name = tags.get('name')
if not name:
name = tags.get('name:en')
elif not name:
name = tags.get('name:ku')
elif applies to all previous conditions and gets only executed if all of the previous conditions evaluated to false. In your case, however, the first if-condition (if not name) already evaluated to true. Therefore your elif-conditions won't get executed. You need to change them to if-conditions instead:
name = tags.get('name')
if not name:
name = tags.get('name:en')
if not name:
name = tags.get('name:ku')
if not name:
name = tags.get('name:ar')
if not name:
name = tags.get('shop','no-name')
The loop-approach suggested by Maurice in https://stackoverflow.com/a/60810856/1340631 is better, though.

Flatten nested List

Not sure if I'm asking this in the right place or if I'm understanding this correctly. I need change the dictionary so that the occurrence field is added on to the availability key. For example: "Availability.Occurrence": "Daily"
BEFORE
test_data = {
"testDate": "2018-11-19 21:00:00",
"testMessage": "This is a test message",
"testStatus": "Warning",
"Results": [
{
"Availability": {
"Occurence": "Daily"
},
"OldestRefreshDate": "2018-11-15 15:40:57 EST",
"TableName": "test"
}
],
"TaskId": "CheckSourceRefreshDates"
}
AFTER
test_data = {
"testDate": "2018-11-19 21:00:00",
"testMessage": "This is a test message",
"testStatus": "Warning",
"Results": [
{
"Availability.Occurrence": "Daily",
"OldestRefreshDate": "2018-11-15 15:40:57 EST",
"TableName": "test"
}
],
"TaskId": "CheckSourceRefreshDates"
}
I am new to Python just trying to figure all this out. Any help is appreciated.
Heres the function that I tried using, however it only flattens the entire dictionary.
def flatten_json(y):
out = {}
def flatten(x, name=''):
if type(x) is dict:
for a in x:
flatten(x[a], name + a + '.')
elif type(x) is list:
i = 0
for a in x:
flatten(a, name + '.')
i += 1
else:
out[name[:-1]] = x
flatten(y)
return out

Django get value from JSON data

I am trying to play with an open fda API. So far everything works well. Issue is coming for nested JSON data.
Here is my Json data:
{
"seriousnessother": "1",
"reportduplicate": {
"duplicatenumb": "US-BRISTOL-MYERS SQUIBB COMPANY-BMS-2017-086135",
"duplicatesource": "BRISTOL MYERS SQUIBB"
},
"safetyreportversion": "1",
"receiptdate": "20170927",
"duplicate": "1",
"seriousnessdeath": "1",
"receivedate": "20170927",
"patient": {
"reaction": [
{
"reactionmeddrapt": "Death",
"reactionmeddraversionpt": "20.1",
"reactionoutcome": "5"
},
{
"reactionmeddrapt": "Product use in unapproved indication",
"reactionmeddraversionpt": "20.1",
"reactionoutcome": "6"
}
],
"patientsex": "1",
"drug": [
{
"drugstartdateformat": "102",
"medicinalproduct": "OPDIVO",
"drugindication": "COLORECTAL CANCER",
"drugcharacterization": "1",
"drugadministrationroute": "065",
"drugenddateformat": "102",
"drugseparatedosagenumb": "1",
"drugstructuredosageunit": "032",
"openfda": {
"manufacturer_name": [
"E.R. Squibb & Sons, L.L.C."
],
"unii": [
"31YO63LBSN"
],
"product_type": [
"HUMAN PRESCRIPTION DRUG"
],
"spl_set_id": [
"f570b9c4-6846-4de2-abfa-4d0a4ae4e394"
],
"route": [
"INTRAVENOUS"
],
"generic_name": [
"NIVOLUMAB"
],
"brand_name": [
"OPDIVO"
],
"product_ndc": [
"0003-3772",
"0003-3734",
"0003-3774"
],
"pharm_class_epc": [
"Programmed Death Receptor-1 Blocking Antibody [EPC]"
],
"substance_name": [
"NIVOLUMAB"
],
"spl_id": [
"2d33126d-5115-459e-bcaf-d0ace4fbe94e"
],
"pharm_class_moa": [
"Programmed Death Receptor-1-directed Antibody Interactions [MoA]"
],
"application_number": [
"BLA125554"
],
"nui": [
"N0000191259",
"N0000191260"
],
"package_ndc": [
"0003-3734-13",
"0003-3772-11",
"0003-3774-12"
]
},
"drugstructuredosagenumb": "1",
"drugintervaldosageunitnumb": "2",
"drugstartdate": "20160907",
"actiondrug": "5",
"activesubstance": {
"activesubstancename": "NIVOLUMAB"
},
"drugintervaldosagedefinition": "803",
"drugauthorizationnumb": "125554",
"drugrecurreadministration": "3",
"drugdosagetext": "1 DF, Q2WK",
"drugenddate": "20161222",
"drugadditional": "3"
}
]
},
"occurcountry": "US",
"reporttype": "1",
"companynumb": "US-BRISTOL-MYERS SQUIBB COMPANY-BMS-2017-086135",
"safetyreportid": "14015990",
"sender": {
"senderorganization": "FDA-Public Use",
"sendertype": "2"
},
"transmissiondate": "20171128",
"fulfillexpeditecriteria": "1",
"transmissiondateformat": "102",
"receiptdateformat": "102",
"receiver": {
"receiverorganization": "FDA",
"receivertype": "6"
},
"serious": "1",
"receivedateformat": "102",
"primarysource": {
"reportercountry": "US",
"qualification": "5"
},
"primarysourcecountry": "US"
}
Here is my view to call this data and convert to Django data.
json_data = open('/users/downloads/drug-bad.json').read()
response = json.loads(json_data)
a=0
b=0
for data in response['results']:
#try:
seriousnessother = data.get('seriousnessother')
reportduplicate_duplicatenumb = data['reportduplicate'].get('duplicatenumb')
reportduplicate_duplicatesource = data['reportduplicate'].get('duplicatesource')
safetyreportversion = data.get('safetyreportversion')
receiptdate = data.get('receiptdate')
duplicate = data.get('duplicate')
seriousnessdeath = data.get('seriousnessdeath')
receivedate = data.get('receivedate')
patient_reaction_reactionmeddrapt = data['patient']['reaction'].get('reactionmeddrapt')
patient_reaction_reactionmeddraversionpt = data['patient']['reaction'].get('reactionmeddraversionpt')
patient_reaction_reactionoutcome = data['patient']['reaction'].get('reactionoutcome')
patient_patientsex = data['patient'].get('patientsex')
patient_drug_medicinalproduct = data['patient']['drug'].get('medicinalproduct')
patient_drug_drugindication = data['patient']['drug'].get('drugindication')
patient_drug_drugcharacterization = data['patient']['drug'].get('drugcharacterization')
patient_drug_drugadministrationroute = data['patient']['drug'].get('drugadministrationroute')
patient_drug_drugseparatedosagenumb = data['patient']['drug'].get('drugseparatedosagenumb')
patient_drug_drugstructuredosageunit = data['patient']['drug'].get('drugstructuredosageunit')
patient_drug_openfda_manufacturer_name = data['patient']['drug']['openfda']['manufacturer'].get('name')
patient_drug_openfda_unii = data['patient']['drug']['openfda'].get('unii')
patient_drug_openfda_product_type = data['patient']['drug']['openfda']['product'].get('type')
patient_drug_openfda_spl_set_id = data['patient']['drug']['openfda']['spl']['set'].get('id')
patient_drug_openfda_route = data['patient']['drug']['openfda'].get('route')
patient_drug_openfda_generic_name = data['patient']['drug']['openfda']['generic'].get('name')
patient_drug_openfda_brand_name = data['patient']['drug']['openfda']['brand'].get('name')
patient_drug_openfda_product_ndc = data['patient']['drug']['openfda']['product'].get('ndc')
patient_drug_openfda_pharm_class_epc = data['patient']['drug']['openfda']['pharm']['class'].get('epc')
patient_drug_openfda_substance_name = data['patient']['drug']['openfda']['substance'].get('name')
patient_drug_openfda_spl_id = data['patient']['drug']['openfda']['spl'].get('id')
patient_drug_openfda_pharm_class_moa = data['patient']['drug']['openfda']['pharm']['class'].get('moa')
patient_drug_openfda_application_number = data['patient']['drug']['openfda']['application'].get('number')
patient_drug_openfda_nui = data['patient']['drug']['openfda'].get('nui')
patient_drug_openfda_package_ndc = data['patient']['drug']['openfda']['package'].get('ndc')
patient_drug_drugstructuredosagenumb = data['patient']['drug'].get('drugstructuredosagenumb')
patient_drug_drugintervaldosageunitnumb = data['patient']['drug'].get('drugintervaldosageunitnumb')
patient_drug_drugstartdate = data['patient']['drug'].get('drugstartdate')
patient_drug_actiondrug = data['patient']['drug'].get('actiondrug')
patient_drug_activesubstance_activesubstancename = data['patient']['drug']['activesubstance'].get('activesubstancename')
patient_drug_drugintervaldosagedefinition = data['patient']['drug'].get('drugintervaldosagedefinition')
patient_drug_drugauthorizationnumb = data['patient']['drug'].get('drugauthorizationnumb')
patient_drug_drugrecurreadministration = data['patient']['drug'].get('drugrecurreadministration')
patient_drug_drugdosagetext = data['patient']['drug'].get('drugdosagetext')
patient_drug_drugenddate = data['patient']['drug'].get('drugenddate')
patient_drug_drugadditional = data['patient']['drug'].get('drugadditional')
occurcountry = data.get('occurcountry')
reporttype = data.get('reporttype')
companynumb = data.get('companynumb')
safetyreportid = data.get('safetyreportid')
sender_senderorganization = data['sender'].get('senderorganization')
sender_sendertype = data['sender'].get('sendertype')
fulfillexpeditecriteria = data.get('fulfillexpeditecriteria')
receiver_receiverorganization = data['receiver'].get('receiverorganization')
receiver_receivertype = data['receiver'].get('receivertype')
serious = data.get('serious')
primarysource_reportercountry = data['primarysource'].get('reportercountry')
primarysource_qualification = data['primarysource'].get('qualification')
primarysourcecountry = data.get('primarysourcecountry')
I am getting following error:
patient_reaction_reactionmeddrapt = data['patient']['reaction'].get('reactionmeddrapt')
AttributeError: 'list' object has no attribute 'get'
Note that there are many data in response result. It could be that one of result does not have patient field. But as get method should return None if it does not exist.
I want either the field value or None.
It works for simple Json data but error comes when there are array/list inside array/list.
Since reaction is list you should do something like this:
reactions = data['patient']['reaction']
if reactions and isinstance(reactions, list):
for reaction in reactions:
patient_reaction_reactionmeddrapt = reaction.get('reactionmeddrapt')
else:
patient_reaction_reactionmeddrapt = data['patient']['reaction'].get('reactionmeddrapt')
instead of simple:
patient_reaction_reactionmeddrapt = data['patient']['reaction'].get('reactionmeddrapt')
data['patient']['reaction'] in your code return list objects. So you need to iterate over it to get reactionmeddrapt for each list element.
Given your input json:
"patient": {
"reaction": [
{
"reactionmeddrapt": "Death",
"reactionmeddraversionpt": "20.1",
"reactionoutcome": "5"
},
{
"reactionmeddrapt": "Product use in unapproved indication",
"reactionmeddraversionpt": "20.1",
"reactionoutcome": "6"
}
],
The data value for "reactions" is a list. Also as I understand it, you want to get the "reactionmeddrapt" attribute value or None if you don't have a data value for "patient".
You could do something like this:
try:
reactions = data['patient']['reaction']
except KeyError:
return None
if reactions and isinstance(reactions, list):
# Assuming you want to iterate over the list
for reaction in reactions:
reactionmeddrapt = reaction.get('reactionmeddrapt')

Categories

Resources