How to extract a key pair value from a JSON array? - python

I'm using a GET query string to locate a specific record. The correct result is returned in JSON, but in an array of one (it allows for multiple items, but as I'm using a unique key in my query string, there will only ever be one item returned, but's it's still in an array). I've been able to extract the value of a specific key pair from a JSON result before, but this time the fact that this particular result is in an array has got me stumped. I'm a set of square brackets away from success :-(
Here's the JSON response, and I want the value of 'Id':
{
'#odata.context': 'https://foo.bar.com/mySite/api/v2/object/$metadata#MuseuSensorData_SensorDeviceObject',
'value':
[
{
'Id': '02cb9c0f-89ca-46fd-882e-5d770d7da214',
'DateCreated': '2022-07-13T14:05:22.24+01:00',
'DeviceName': 'Cabinet 2 Sensor 1',
'IsActive': True,
'SerialNumber': '1234'
}
]}
In amongst my Python code, extract below, I'm trying to return the value of 'Id', but all I get is any one of a number of errors (latest is TypeError: string indices must be integers), which I know relates to indices/dictionaries and something called slices, and navigating through to the desired section, but I'm new to Python (as of this week), and it's got me spinning.
response = requests.request("GET", url, headers=headers)
data = response.text
print(data[0]['value']['Id'])

Looks like I was almost there. Thanks to Kacper, I now have my code in the right order:
data = response.text
parsed_json = json.loads(data)
RecID = parsed_json['value'][0]['Id']
print(RecID)

Related

keyerror while checking for values that exists in a dictionary

I keep getting a keyerror in python.
I am using requests and getting back a json with 3 values. I am trying to extract only the elevation.
r = requests.get(api_url +str(lat) +"," +str(longi) )
resp = json.loads(r.text)
print(resp)
print(resp['elevation'])
this is the response for resp:
{'results': [{'latitude': 30.654543, 'longitude': 35.235351, 'elevation': -80}]}
this is the error:
KeyError: 'elevation'
If you format the JSON (resp) a bit to be easier to undestand, you get something like this:
{
"results":[
{
"latitude":30.654543,
"longitude":35.235351,
"elevation":-80
}
]
}
(I used this tool)
You can see that the "toplevel" is an object (loaded as a python dict) with a single key: "results", containing an array of objects (loaded as a python list of dicts).
resp['results'] would be [{'latitude': 30.654543, 'longitude': 35.235351, 'elevation': -80}] - the said array
resp['results'][0] would be the 1st element of that array: {'latitude': 30.654543, 'longitude': 35.235351, 'elevation': -80}
resp['results'][0]['elevation'] would be -80
I suggest using a for loop to iterate trough the elements of resp['results'] to process all resoults.
It is responding with a list (holding one dictionary) as the value. So you would access with resp["results"][0]["elevation"] because "elevation" is not in results, it is in results[0] (zero index of the list results) and you can tell this by the "[{ }]" denoting a list holding a dictionary.
The response is a dictionary whose 'results' key holds a list of dictionaries. In your case this list holds only one entry. So, you must traverse the entire path to get the value you want.
Try:
resp['results'][0]['elevation']

I can't get a value from a JSON API response in python

So I am struggling with getting a value from a JSON response. Looking in other post I have managed to write this code but when I try to search for the key (character_id) that I want in the dictionary python says that the key doesn't exist. My solution consists in getting the JSON object from the response, converting it into a string with json.dumps() and the converting it into a dictionary with json.loads(). Then I try to get 'character_id' from the dictionary but it doesn't exist. I am guessing it is related with the format of the dictionary but I have little to none experience in python. The code that makes the query and tries to get the values is this: (dataRequest is a fuction that makes the request and return the response from the api)
characterName = sys.argv[1];
response = dataRequest('http://census.daybreakgames.com/s:888/get/ps2:v2/character/?name.first_lower=' + characterName + '&c:show=character_id')
jsonString = json.dumps(response.json())
print(jsonString)
dic = json.loads(jsonString)
print(dic)
if 'character_id' in dic:
print(dic['character_id'])
The output of the code is:
{"character_list": [{"character_id": "5428662532301799649"}], "returned": 1}
{'character_list': [{'character_id': '5428662532301799649'}], 'returned': 1}
Welcome #Prieto! From what I can see, you probably don't need to serialize/de-serialize the JSON -- response.json() returns a python dictionary object already.
The issue is that you are looking for the 'character_id' key at the top-level of the dictionary, when it seems to be embedded inside another dictionary, that is inside a list. Try something like this:
#...omitted code
for char_obj in dic["character_list"]:
if "character_id" in char_obj:
print(char_obj["character_id"])
if your dic is like {"character_list": [{"character_id": "5428662532301799649"}], "returned": 1}
you get the value of character_id by
print(dic['character_list'][0][character_id])
The problem here is that you're trying to access a dictionary where the key is actually character_list.
What you need to do is to access the character_list value and iterate over or filter the character_id you want.
Like this:
print(jsonString)
dic = json.loads(jsonString)
print(dic)
character_information = dic['character_list'][0] # we access the character list and assume it is the first value
print(character_information["character_id"]) # this is your character id
The way I see it, the only hiccup with the code is this :
if 'character_id' in dic:
print(dic['character_id'])
The problem is that, the JSON file actually consists of actually 2 dictionaries , first is the main one, which has two keys, character_list and returned. There is a second sub-dictionary inside the array, which is the value for the key character_list.
So, what your code should actually look like is something like this:
for i in dic["character_list"]:
print(i["character_id"])
On a side-note, it will help to look at JSON file in this way :
{
"character_list": [
{
"character_id": "5428662532301799649"
}
],
"returned": 1
}
,where, elements enclosed in curly-brackets'{}' imply they are in a dictionary, whereas elements enclosed in curly-brackets'[]' imply they are in a list

Yet another Python looping over JSON array

I spent several hours on this, tried everything I found online, pulled some of the hair left on my head...
I have this JSON sent to a Flask webservice I'm writing :
{'jsonArray': '[
{
"nom":"0012345679",
"Start":"2018-08-01",
"Finish":"2018-08-17",
"Statut":"Validee"
},
{
"nom":"0012345679",
"Start":"2018-09-01",
"Finish":"2018-09-10",
"Statut":"Demande envoyée au manager"
},
{
"nom":"0012345681",
"Start":"2018-04-01",
"Finish":"2018-04-08",
"Statut":"Validee"
},
{
"nom":"0012345681",
"Start":"2018-07-01",
"Finish":"2018-07-15",
"Statut":"Validee"
}
]'}
I want to simply loop through the records :
app = Flask(__name__)
#app.route('/graph', methods=['POST'])
def webhook():
if request.method == 'POST':
req_data = request.get_json()
print(req_data) #-> shows JSON that seems to be right
##print(type(req_data['jsonArray']))
#j1 = json.dumps(req_data['jsonArray'])
#j2 = json.loads(req_data['jsonArray'])
#data = json.loads(j1)
#for rec in data:
# print(rec) #-> This seems to consider rec as one of the characters of the whole JSON string, and prints every character one by one
#for key in data:
# value = data[key]
# print("The key and value are ({}) = ({})".format(key, value)) #-> TypeError: string indices must be integers
for record in req_data['jsonArray']:
for attribute, value in rec.items(): #-> Gives error 'str' object has no attribute 'items'
print(attribute, value)
I believe I am lost between JSON object, python dict object, strings, but I don't know what I am missing. I really tried to put the JSON received through json.dumps and json.loads methods, but still nothing. What am I missing ??
I simply want to loop through each record to create another python object that I will feed to a charting library like this :
df = [dict(Task="0012345678", Start='2017-01-01', Finish='2017-02-02', Statut='Complete'),
dict(Task="0012345678", Start='2017-02-15', Finish='2017-03-15', Statut='Incomplete'),
dict(Task="0012345679", Start='2017-01-17', Finish='2017-02-17', Statut='Not Started'),
dict(Task="0012345679", Start='2017-01-17', Finish='2017-02-17', Statut='Complete'),
dict(Task="0012345680", Start='2017-03-10', Finish='2017-03-20', Statut='Not Started'),
dict(Task="0012345680", Start='2017-04-01', Finish='2017-04-20', Statut='Not Started'),
dict(Task="0012345680", Start='2017-05-18', Finish='2017-06-18', Statut='Not Started'),
dict(Task="0012345681", Start='2017-01-14', Finish='2017-03-14', Statut='Complete')]
The whole thing is wrapped in single quotes, meaning it's a string and you need to parse it.
for record in json.loads(req_data['jsonArray']):
Looking at your commented code, you did this:
j1 = json.dumps(req_data['jsonArray'])
data = json.loads(j1)
Using json.dumps on a string is the wrong idea, and moreover json.loads(json.dumps(x)) is just the same as x, so that just got you back where you started, i.e. data was the same thing as req_data['jsonArray'] (a string).
This was the right idea:
j2 = json.loads(req_data['jsonArray'])
but you never used j2.
As you've seen, iterating over a string gives you each character of the string.

Add element to JSON in Python

There are few topics regarding this, however, neither of them helped me in a way I need.
I would need to parse json by (some) fields that user enters, meaning the user can fill 3 out of 7 fields, leaving 4 empty. I cannot put attribute with an empty value to json, thus I need join only the entered ones.
This is where my issue comes, can't figure out the correct way to glue together, for example, nw_src with IP address (appearing as one variable) together with nw_proto, dl_type and potentially others, in the match attribute. In this code, Python expects comma instead of the colon between nw_proto and 1.
data2 = {}
data2['nw_src'] = '10.0.0.5' #or variable
json_data = json.dumps(data2)
data = {"dpid": "1", "priority": "65500", "table_id": "0", "match":
{data2, 'nw_proto': '1', 'dl_type': '2048'}}
r = requests.post('http://localhost:8080/stats/flowentry/add', data=json.dumps(data))
I tried this way, also with json_data and something like this:
data[0]['f'] = var
no one did the trick and resulted in error. Any ideas?
{data2, 'nw_proto': '1', 'dl_type': '2048'} is not the right way of merging two dictionaries as one.
Assuming you are using Python 2.7, you can either use dict with unpacking the rest:
data = {..., "match": dict(data2, **{'nw_proto': '1', 'dl_type': '2048'})
or .update() before putting into the actual dict:
data2.update({'nw_proto': '1', 'dl_type': '2048'})
data = {..., "match": data2}

Parsing Python JSON with multiple same strings with different values

I am stuck on an issue where I am trying to parse for the id string in JSON that exists more than 1 time. I am using the requests library to pull json from an API. I am trying to retrieve all of the values of "id" but have only been able to successfully pull the one that I define. Example json:
{
"apps": [{
"id": "app1",
"id": "app2",
"id": "new-app"
}]
}
So what I have done so far is turn the json response into dictionary so that I am actually parse the first iteration of "id". I have tried to create for loops but have been getting KeyError when trying to find string id or TypeError: list indices must be integers or slices, not str. The only thing that I have been able to do successfully is define which id locations to output.
(data['apps'][N]['id']) -> where N = 0, 1 or 2
This would work if there was only going to be 1 string of id at a time but will always be multiple and the location will change from time to time.
So how do return the values of all strings for "id" from this single json output? Full code below:
import requests
url = "http://x.x.x.x:8080/v2/apps/"
response = requests.get(url)
#Error if not 200 and exit
ifresponse.status_code!=200:
print("Status:", response.status_code, "CheckURL.Exiting")
exit()
#Turn response into a dict and parse for ids
data = response.json()
for n in data:
print(data['apps'][0]['id'])
OUTPUT:
app1
UPDATE:
Was able to get resolution thanks to Robᵩ. Here is what I ended up using:
def list_hook(pairs):
result = {}
for name, value in pairs:
if name == 'id':
result.setdefault(name, []).append(value)
print(value)
data = response.json(object_pairs_hook = list_hook)
Also The API that I posted as example is not a real API. It was just supposed to be a visual representation of what I was trying to achieve. I am actually using Mesosphere's Marathon API . Trying to build a python listener for port mapping containers.
Your best choice is to contact the author of the API and let him know that his data format is silly.
Your next-best choice is to modify the behavior of the the JSON parser by passing in a hook function. Something like this should work:
def list_hook(pairs):
result = {}
for name, value in pairs:
if name == 'id':
result.setdefault(name, []).append(value)
else:
result[name] = value
return result
data = response.json(object_pairs_hook = list_hook)
for i in range(3):
print(i, data['apps'][0]['id'][i])

Categories