Travers through a nested json object and store values- Python - python

This is a follow up on this question. Question
Also this question is similar but does not solve my problem Question2
I am trying to parse a nested json to get Check how many children a specific location has, I am trying to check if "children:" = None and increment counter to check how many levels down i need to go in order to get the lowest child, or
A more efficient solution would be:
I need to get all the child values into a list and keep going until "children:" = None.
The Json object can increase in the amount of children so we can have multiple level of children, Which can get messy if I want to nest the list and get the values, How could I do it dynamically?
{
'locationId': 'location1',
'name': 'Name',
'type': 'Ward',
'patientId': None,
'children': [{
'locationId': 'Child_location2',
'name': 'Name',
'type': 'Bed',
'patientId': None,
'children': [{
'locationId': 'Child_Child_location3',
'name': 'Name',
'type': 'HospitalGroup',
'patientId': None,
'children': None
}]
}, {
'locationId': 'location4',
'name': 'Name',
'type': 'Hospital',
'patientId': None,
'children': None
}, {
'locationId': 'location5',
'name': 'Name',
'type': 'Bed',
'patientId': None,
'children': None
}, {
'locationId': 'location6',
'name': 'Name',
'type': 'Bed',
'patientId': None,
'children': None
}, {
'locationId': 'location27',
'name': 'Name',
'type': 'Bed',
'patientId': None,
'children': None
}]
}
I tried to do something like this
import requests
def Get_Child(URL, Name):
headers = {
'accept': 'text/plain',
}
response = requests.get(
URL + Name,
headers=headers)
json_data = response.json()
print (json_data)
list = []
for locationId in json_data['locationId']:
list.append(locationId)
for children in locationId['children']:
list.append(children)
but that give me the following error,
for children in locationId['locationId']: TypeError: string indices must be integers

Your code shows append, but you ask for a count. Here is a recursive way to get the number of children in this JSON if I am understanding you correctly:
def get_children(body, c=1):
if not body.get('children'):
c += 1
elif isinstance(body.get('children'), list):
c += 1
for subchild in body.get('children'):
c += 1
get_children(subchild, c)
return c
counts = get_children(your_json_blob)
print(counts)
>>> 7
Edit: I purposely did not use if/else because I don't know if you can have subchildren that are dict rather than list which would mean you would need extra conditions, but that's up to you if that ends up being the case.

I found a solution fro my problem,
The following code will get all the children and append them to a list
class Children():
def Get_All_Children(self,json_input, lookup_key):
if isinstance(json_input, dict):
for k, v in json_input.items():
if k == lookup_key:
yield v
else:
yield from self.Get_All_Children(v, lookup_key)
elif isinstance(json_input, list):
for item in json_input:
yield from self.Get_All_Children(item, lookup_key)
for locations in self.Get_All_Children(self.json_data, 'locationId'):
self.mylist.append(locations)

Related

How to get multiple key value pairs from list of JSON dictionaries

I have a JSON file called "hostnames" formatted like below
{
'propertyName': 'www.property1.com',
'propertyVersion': 1,
'etag': 'jbcas6764023nklf78354',
'rules': {
'name': 'default',
'children': [{
'name': 'Route',
'children': [],
'behaviors': [{
'name': 'origin',
'options': {
'originType': 'CUSTOMER',
'hostname': 'www.origin1.com',
and I wanted to get the values of keys "propertyName" and "hostname" and have a new JSON file like below
'properties': [{
'propertyName': 'www.property1.com',
'hostnames': ['www.origin1.com', 'www.origin2.com']
}, {
'propertyName': 'www.property1.com',
'hostnames': ['www.origin1.com', 'www.origin2.com']
}]
my code looks like this
hostnames = result.json()
hostnameslist = [host['hostname'] for host in hostnames['rules']['children']['behaviors']['options']]
print(hostnameslist)
but I'm getting the error
TypeError: list indices must be integers or slices, not str
You are trying to access a list elements with a string index ('behaviors').
Try:
hostnames = result.json()
hostnameslist = []
for child in hostnames['rules']['children']:
for behavior in child['behaviors']:
if behavior['name'] == 'origin':
hostnameslist.append(behavior['options']['hostname'])
properties = [{
'propertyName': hostnames['propertyName'],
'hostnames': hostnameslist
}]
Making an assumption about how the OP's data might be structured.
Recursive navigation of the dictionary to find all/any values associated with a dictionary key of 'hostname' appears to be well-suited here.
Doing it this way obviates the need for knowledge about the depth of the dictionary or indeed any of the dictionary key names except (obviously) 'hostname'.
Of course, there may be other dictionaries within the "master" dictionary that contain a 'hostname' key. If that's the case then this function may return values that are not needed/wanted.
data = {
'propertyName': 'www.property1.com',
'propertyVersion': 1,
'etag': 'jbcas6764023nklf78354',
'rules': {
'name': 'default',
'children': [{
'name': 'Route',
'children': [],
'behaviors': [{
'name': 'origin',
'options': {
'originType': 'CUSTOMER',
'hostname': 'www.origin1.com'
}
},
{
'name': 'origin',
'options': {
'originType': 'CUSTOMER',
'hostname': 'www.origin2.com'
}
}
]
}
]
}
}
def get_hostnames(d):
def _get_hostnames(_d, _l):
if isinstance(_d, dict):
if 'hostname' in _d:
_l.append(_d['hostname'])
else:
for _v in _d.values():
_get_hostnames(_v, _l)
else:
if isinstance(_d, list):
for _v in _d:
_get_hostnames(_v, _l)
return _l
return _get_hostnames(d, [])
result = {'properties': [{'propertyName': data.get('propertyName'), 'hostnames': get_hostnames(data)}]}
print(result)
Output:
{'properties': [{'propertyName': 'www.property1.com', 'hostnames': ['www.origin1.com', 'www.origin2.com']}]}

How to add list into api call last array?

I have this code the call an api and get an answer.
I need to perform a call for ever issue_id, and store the issue id with the correct response:
issues_ids = [10495]
def get_changelog(issue_id: int):
url = f'{base_url}/{issue_id}/changelog'
response = requests.request("GET",url,headers=headers,auth=auth)
return (response.json())
def parse_json(response):
keylsit = []
for item in response['values']:
key = {
'id': item['id'],
'items': item['items']
}
(keylsit.append(key))
return keylsit
mainlist = []
for i in issues_ids:
print(i)
mainlist.extend(parse_json(get_changelog(i)))
print(mainlist)
current print :
10495
[{'id': '13613', 'items': [{'field': 'Organization text', 'fieldtype': 'custom', 'fieldId': 'customfield_10039', 'from': None, 'fromString': None, 'to': None, 'toString': 'Jabil'}]}]
I need to add the 10495 with in this array as a new key
[{issue_id: 10495, 'id': '13613', 'items': [{'field': 'Organization text', 'fieldtype': 'custom', 'fieldId': 'customfield_10039', 'from': None, 'fromString': None, 'to': None, 'toString': 'Jabil'}]}]
I tried different methods such as insert, append...

Python: when trying to extract certain keys, how can I avoid a KeyError when in some dict elements, the key value is missing from APi json?

I can successfully extract every column using Python, except the one I need most (order_id) from an API generated json that lists field reps interactions with clients.
Not all interactions result in orders; there are multiple types of interactions. I know I will need to add the flag to show 'None' and then in my for loop and an if-statement to check whether the order_id is null or not. If not 'None/null', add it to the list.
I just cannot figure it out so would appreciate every bit of help!
This is the code that works:
import requests
import json
r = requests.get(baseurl + endpoint + '?page_number=1' + '&page_size=2', headers=headers)
output = r.json()
interactions_list = []
for item in output['data']:
columns = {
'id': item['id'],
'number': item['user_id'],
'name': item['user_name'],
}
interactions_list.append(columns)
print(interactions_list)
This returns an error-free result:
[{'id': 1, 'number': 6, 'name': 'Johnny'}, {'id': 2, 'number': 7, 'name': 'David'}]
When I include the order_id in the loop:
interactions_list = []
for item in output['data']:
columns = {
'id': item['id'],
'number': item['user_id'],
'name': item['user_name'],
'order': item['order_id'],
}
interactions_list.append(columns)
It returns:
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_17856/1993147086.py in <module>
6 'number': item['user_id'],
7 'name': item['user_name'],
----> 8 'order': item['order_id'],
9 }
10
KeyError: 'order_id'
Use the get method of the dictionary:
columns = {
'id': item.get('id'),
'number': item.get('user_id'),
'name': item.get('user_name'),
'order': item.get('order_id'),
}
This will set your missing values to None. If you want to choose what the None value is, pass a second argument to get e.g. item.get('user_name', 'N/A')
EDIT: To conditionally add items based on the presence of the order_id
interactions_list = []
for item in output['data']:
if 'order_id' in item:
columns = {
'id': item.get('id'),
'number': item.get('user_id'),
'name': item.get('user_name', 'N/A'),
'order': item.get('order_id'),
}
interactions_list.append(columns)
Alternatively, you can use a list comprehension approach, which should be slightly more efficient than using list.append in a loop:
output = {'data': [{'order_id': 'n/a', 'id': '123'}]}
interactions_list = [
{
'id': item.get('id'),
'number': item.get('user_id'),
'name': item.get('user_name', 'N/A'),
'order': item.get('order_id'),
} for item in output['data'] if 'order_id' in item
]
# [{'id': '123', 'number': None, 'name': 'N/A', 'order': 'n/a'}]

How to iterate over nested list of dictionaries?

I need to get the 'ids' of this json response,the thing is that, there are many dictionaries with a list of dictionaries inside,how can I do this??(PS:len(items) is 20,so I need to get the 20 ids in the form of a dictionary.
{'playlists': {'href': 'https://api.spotify.com/v1/search?query=rewind-The%25&type=playlist&offset=0&limit=20',
'items': [{'collaborative': False,
'description': 'Remember what you listened to in 2010? Rewind and rediscover your favorites.',
'external_urls': {'spotify': 'https://open.spotify.com/playlist/37i9dQZF1DXc6IFF23C9jj'},
'href': 'https://api.spotify.com/v1/playlists/37i9dQZF1DXc6IFF23C9jj',
'id': '37i9dQZF1DXc6IFF23C9jj',
'images': [{'height': None,
'url': 'https://i.scdn.co/image/ab67706f0000000327ba1078080355421d1a49e2',
'width': None}],
'name': 'Rewind - The Sound of 2010',
'owner': {'display_name': 'Spotify',
'external_urls': {'spotify': 'https://open.spotify.com/user/spotify'},
'href': 'https://api.spotify.com/v1/users/spotify',
'id': 'spotify',
'type': 'user',
'uri': 'spotify:user:spotify'},
'primary_color': None,
'public': None,
'snapshot_id': 'MTU5NTUzMTE1OSwwMDAwMDAwMGQ0MWQ4Y2Q5OGYwMGIyMDRlOTgwMDk5OGVjZjg0Mjdl',
'tracks': {'href': 'https://api.spotify.com/v1/playlists/37i9dQZF1DXc6IFF23C9jj/tracks',
'total': 100},
'type': 'playlist',
'uri': 'spotify:playlist:37i9dQZF1DXc6IFF23C9jj'},
Im trying to get it through this:
dict={'id':''}
for playlists in playlist_data['playlists']:
for items in playlists['items']:
for item in items:
for dic in range(len(item)):
for id in dic['id']:
dict.update('id')
print(dict)
I get this error:
TypeError: string indices must be integers ```
Try something like this:
ids = [item["id"] for item in json_data["playlists"]["items"]]
This is called a list comprehension.
You want to iterate over all of the "items" within the "playlists" key.
You can access that list of items:
json_data["playlists"]["items"]
Then you iterate over each item within items:
for item in json_data["playlists"]["items"]
Then you access the "id" of each item:
item["id"]
You can index an object using the keys of object. I can see there are two places where id is present in an object. To retrieve those two ids and store them in a dictionary format, you can use the following approach -
_json = {
'playlists': {
'href': 'https://api.spotify.com/v1/search?query=rewind-The%25&type=playlist&offset=0&limit=20',
'items': [{
'collaborative': False,
'description': 'Remember what you listened to in 2010? Rewind and rediscover your favorites.',
'external_urls': {
'spotify': 'https://open.spotify.com/playlist/37i9dQZF1DXc6IFF23C9jj'
},
'href': 'https://api.spotify.com/v1/playlists/37i9dQZF1DXc6IFF23C9jj',
'id': '37i9dQZF1DXc6IFF23C9jj',
'images': [{
'height': None,
'url': 'https://i.scdn.co/image/ab67706f0000000327ba1078080355421d1a49e2',
'width': None
}],
'name': 'Rewind - The Sound of 2010',
'owner': {
'display_name': 'Spotify',
'external_urls': {
'spotify': 'https://open.spotify.com/user/spotify'
},
'href': 'https://api.spotify.com/v1/users/spotify',
'id': 'spotify',
'type': 'user',
'uri': 'spotify:user:spotify'
},
'primary_color': None,
'public': None,
'snapshot_id': 'MTU5NTUzMTE1OSwwMDAwMDAwMGQ0MWQ4Y2Q5OGYwMGIyMDRlOTgwMDk5OGVjZjg0Mjdl',
'tracks': {
'href': 'https://api.spotify.com/v1/playlists/37i9dQZF1DXc6IFF23C9jj/tracks',
'total': 100
},
'type': 'playlist',
'uri': 'spotify:playlist:37i9dQZF1DXc6IFF23C9jj'
}, ]
}
}
res_dict = {'id':[items['id'], items['owner']['id']] for items in _json['playlists']['items']}
print(res_dict)
OUTPUT :
{'id': ['37i9dQZF1DXc6IFF23C9jj', 'spotify']}
If you don't need the second id that's present in the json object, you can just remove it from above res_dict and modify it as -
res_dict = {'id':items['id'] for items in _json['playlists']['items']}
This will only fetch the id present in the items array as key of any element and not any further nested ids (like items[i]->owner->id won't be in the final res as it was in the fist case ).

How can I recursively add dictionaries in Python from JSON?

Dear Stackoverflow Members,
I have this JSON array, and it consists of the following items (basically):
{
{
'Name': 'x',
'Id': 'y',
'Unsusedstuff' : 'unused',
'Unsusedstuff2' : 'unused2',
'Children': []
},
{ 'Name' : 'xx',
'Id': 'yy',
'Unsusedstuff' : 'unused',
'Unsusedstuff2' : 'unused2',
'Children': [{
'Name': 'xyx',
'Id' : 'yxy',
'Unsusedstuff' : 'unused',
'Unsusedstuff2' : 'unused2',
'Children: []
}
You get the basic idea. I want to emulate this (and just grab the id and the name and the structure) in a Python-list using the following code:
names = []
def parseNames(col):
for x in col:
if(len(x['Children'])> 0):
names.append({'Name' : x['Name'], 'Id' : x['Id'], 'Children' : parseNames(x['Children'])})
else:
return {'Name' : x['Name'], 'Id' : x['Id']}
But, it only seems to return the first 'root' and the first nested folder, but doesn't loop through them all.
How would I be able to fix this?
Greetings,
Mats
The way I read this, you're trying to convert this tree into a tree of nodes which only have Id, Name and Children. In that case, the way I'd think of it is as cleaning nodes.
To clean a node:
Create a node with the Name and Id of the original node.
Set the new node's Children to be the cleaned versions of the original node's children. (This is the recursive call.)
In code, that would be:
def clean_node(node):
return {
'Name': node['Name'],
'Id': node['Id'],
'Children': map(clean_node, node['Children']),
}
>>> print map(clean_node, data)
[{'Name': 'x', 'Children': [], 'Id': 'y'}, {'Name': 'xx', 'Children': [{'Name': 'xyx', 'Children': [], 'Id': 'yxy'}], 'Id': 'yy'}]
I find it's easier to break recursive problems down like this - trying to use global variables turns simple things very confusing very quickly.
Check this
def parseNames(col):
for x in col:
if(len(x['Children'])> 0):
a = [{
'Name' : x['Name'],
'Id' : x['Id'],
'Children' : x['Children'][0]['Children']
}]
parseNames(a)
names.append({'Name' : x['Name'], 'Id' : x['Id']})
return names
Output I get is
[{'Name': 'x', 'Id': 'y'}, {'Name': 'xx', 'Id': 'yy'}, {'Name': 'xx', 'Id': 'yy'}]
You can parse a Json object with this:
import json
response = json.loads(my_string)
Now response is a dictionary with the keys of every Json object.

Categories

Resources