Add element to JSON in Python - 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}

Related

get value by key from json data with python [duplicate]

I have some JSON data like:
{
"status": "200",
"msg": "",
"data": {
"time": "1515580011",
"video_info": [
{
"announcement": "{\"announcement_id\":\"6\",\"name\":\"INS\\u8d26\\u53f7\",\"icon\":\"http:\\\/\\\/liveme.cms.ksmobile.net\\\/live\\\/announcement\\\/2017-08-18_19:44:54\\\/ins.png\",\"icon_new\":\"http:\\\/\\\/liveme.cms.ksmobile.net\\\/live\\\/announcement\\\/2017-10-20_22:24:38\\\/4.png\",\"videoid\":\"15154610218328614178\",\"content\":\"FOLLOW ME PLEASE\",\"x_coordinate\":\"0.22\",\"y_coordinate\":\"0.23\"}",
"announcement_shop": "",
etc.
How do I grab the content "FOLLOW ME PLEASE"? I tried using
replay_data = raw_replay_data['data']['video_info'][0]
announcement = replay_data['announcement']
But now announcement is a string representing more JSON data. I can't continue indexing announcement['content'] results in TypeError: string indices must be integers.
How can I get the desired string in the "right" way, i.e. respecting the actual structure of the data?
In a single line -
>>> json.loads(data['data']['video_info'][0]['announcement'])['content']
'FOLLOW ME PLEASE'
To help you understand how to access data (so you don't have to ask again), you'll need to stare at your data.
First, let's lay out your data nicely. You can either use json.dumps(data, indent=4), or you can use an online tool like JSONLint.com.
{
'data': {
'time': '1515580011',
'video_info': [{
'announcement': ( # ***
"""{
"announcement_id": "6",
"name": "INS\\u8d26\\u53f7",
"icon": "http:\\\\/\\\\/liveme.cms.ksmobile.net\\\\/live\\\\/announcement\\\\/2017-08-18_19:44:54\\\\/ins.png",
"icon_new": "http:\\\\/\\\\/liveme.cms.ksmobile.net\\\\/live\\\\/announcement\\\\/2017-10-20_22:24:38\\\\/4.png",
"videoid": "15154610218328614178",
"content": "FOLLOW ME PLEASE",
"x_coordinate": "0.22",
"y_coordinate": "0.23"
}"""),
'announcement_shop': ''
}]
},
'msg': '',
'status': '200'
}
*** Note that the data in the announcement key is actually more json data, which I've laid out on separate lines.
First, find out where your data resides. You're looking for the data in the content key, which is accessed by the announcement key, which is part of a dictionary inside a list of dicts, which can be accessed by the video_info key, which is in turn accessed by data.
So, in summary, "descend" the ladder that is "data" using the following "rungs" -
data, a dictionary
video_info, a list of dicts
announcement, a dict in the first dict of the list of dicts
content residing as part of json data.
First,
i = data['data']
Next,
j = i['video_info']
Next,
k = j[0] # since this is a list
If you only want the first element, this suffices. Otherwise, you'd need to iterate:
for k in j:
...
Next,
l = k['announcement']
Now, l is JSON data. Load it -
import json
m = json.loads(l)
Lastly,
content = m['content']
print(content)
'FOLLOW ME PLEASE'
This should hopefully serve as a guide should you have future queries of this nature.
You have nested JSON data; the string associated with the 'annoucement' key is itself another, separate, embedded JSON document.
You'll have to decode that string first:
import json
replay_data = raw_replay_data['data']['video_info'][0]
announcement = json.loads(replay_data['announcement'])
print(announcement['content'])
then handle the resulting dictionary from there.
The content of "announcement" is another JSON string. Decode it and then access its contents as you were doing with the outer objects.

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

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)

Python Parsing through complex list that is just really 1 string of characters

I parsed a extremely LONG dictionary for the the fields 'zones' to a variable called scanner_data. In the next paragraph I'm showing the type of scanner_data. The next line after that is the contents of scanner_data.
Variable: scanner_data. The type is : <class 'list'>
[{'id': '3', 'name': 'rcomultitfw', ALL THE REST OF THE STRING IS WORTHLESS TO ME. IT WILL GO ON FOR another 700 letters!
I want to parse the name field for the results of rcomultitfw. I've tried .split(). I've tried converting the list thats really a string to a dictionary so I could parse it again, however it crashes or my python skills are not up to par. If you print(scanner_data[1]) it states its out of range so its the only result of this list.
Just for your information this data was taken from tenables with PyTenables.sc, not sure if that will help or not. My end goal is to parse scan zone data from information from individual tenable scanners.
Please Please help. I was enjoying Python programming up until this point, now I'm pulling out my hair and having headaches. Thanks!
If you can post the code and the console details it would be alot better. However, from what's shown, the data returned is of type list and it contains only one index, so functions like ".split()" won't work since they are only meant for variable of type string. What you might be missing is to first get the dictionary wrapped inside the array then try to access this dictionary using the keys. Here is an example:
scanner_data = [{'id': '3', 'name': 'rcomultitfw', 'extras':'ALL THE REST OF THE STRING I'}]
print(scanner_data[0]['name'])
However, since your question is not so clear I'll try to give an answer for other two possible scenarios:
Scenario A, having a dictionary that's wrapped in a string inside the array:
import ast
scanner_data = ["{'id': '3', 'name': 'rcomultitfw', 'extras':'ALL THE REST OF THE STRING I'}"]
dict_data = scanner_data[0]
parsed_dict = ast.literal_eval(dict_data)
print(parsed_dict['name'])
Scenario B, having a faulty dictionary that will ruin the parser:
import ast
scanner_data = ["{'id': '3', 'name': 'rcomultitfw', 'ALL THE REST OF THE STRING I'}"]
dict_data = scanner_data[0]
adjusted_string = dict_data.split(',')
adjusted_string = adjusted_string[0] + "," + adjusted_string[1] + '}'
parsed_dict = ast.literal_eval(adjusted_string)
print(parsed_dict['name'])
This is not the best way to adjust faulty dictionaries but this can work for your own use case and you can but this logic in a loop if you have multiple dictionaries in the scanner_data list

How can I access the nested data in this complex JSON, which includes another JSON document as one of the strings?

I have some JSON data like:
{
"status": "200",
"msg": "",
"data": {
"time": "1515580011",
"video_info": [
{
"announcement": "{\"announcement_id\":\"6\",\"name\":\"INS\\u8d26\\u53f7\",\"icon\":\"http:\\\/\\\/liveme.cms.ksmobile.net\\\/live\\\/announcement\\\/2017-08-18_19:44:54\\\/ins.png\",\"icon_new\":\"http:\\\/\\\/liveme.cms.ksmobile.net\\\/live\\\/announcement\\\/2017-10-20_22:24:38\\\/4.png\",\"videoid\":\"15154610218328614178\",\"content\":\"FOLLOW ME PLEASE\",\"x_coordinate\":\"0.22\",\"y_coordinate\":\"0.23\"}",
"announcement_shop": "",
etc.
How do I grab the content "FOLLOW ME PLEASE"? I tried using
replay_data = raw_replay_data['data']['video_info'][0]
announcement = replay_data['announcement']
But now announcement is a string representing more JSON data. I can't continue indexing announcement['content'] results in TypeError: string indices must be integers.
How can I get the desired string in the "right" way, i.e. respecting the actual structure of the data?
In a single line -
>>> json.loads(data['data']['video_info'][0]['announcement'])['content']
'FOLLOW ME PLEASE'
To help you understand how to access data (so you don't have to ask again), you'll need to stare at your data.
First, let's lay out your data nicely. You can either use json.dumps(data, indent=4), or you can use an online tool like JSONLint.com.
{
'data': {
'time': '1515580011',
'video_info': [{
'announcement': ( # ***
"""{
"announcement_id": "6",
"name": "INS\\u8d26\\u53f7",
"icon": "http:\\\\/\\\\/liveme.cms.ksmobile.net\\\\/live\\\\/announcement\\\\/2017-08-18_19:44:54\\\\/ins.png",
"icon_new": "http:\\\\/\\\\/liveme.cms.ksmobile.net\\\\/live\\\\/announcement\\\\/2017-10-20_22:24:38\\\\/4.png",
"videoid": "15154610218328614178",
"content": "FOLLOW ME PLEASE",
"x_coordinate": "0.22",
"y_coordinate": "0.23"
}"""),
'announcement_shop': ''
}]
},
'msg': '',
'status': '200'
}
*** Note that the data in the announcement key is actually more json data, which I've laid out on separate lines.
First, find out where your data resides. You're looking for the data in the content key, which is accessed by the announcement key, which is part of a dictionary inside a list of dicts, which can be accessed by the video_info key, which is in turn accessed by data.
So, in summary, "descend" the ladder that is "data" using the following "rungs" -
data, a dictionary
video_info, a list of dicts
announcement, a dict in the first dict of the list of dicts
content residing as part of json data.
First,
i = data['data']
Next,
j = i['video_info']
Next,
k = j[0] # since this is a list
If you only want the first element, this suffices. Otherwise, you'd need to iterate:
for k in j:
...
Next,
l = k['announcement']
Now, l is JSON data. Load it -
import json
m = json.loads(l)
Lastly,
content = m['content']
print(content)
'FOLLOW ME PLEASE'
This should hopefully serve as a guide should you have future queries of this nature.
You have nested JSON data; the string associated with the 'annoucement' key is itself another, separate, embedded JSON document.
You'll have to decode that string first:
import json
replay_data = raw_replay_data['data']['video_info'][0]
announcement = json.loads(replay_data['announcement'])
print(announcement['content'])
then handle the resulting dictionary from there.
The content of "announcement" is another JSON string. Decode it and then access its contents as you were doing with the outer objects.

How do I use a for loop when reading from a dictionary that might contain a list of dicts, but might not?

I apologize in advance that the title is so confusing. It makes a lot more sense in code, so here goes:
I am parsing data from a REST API that returns JSON, and I have a bit of an issue with this particular structure:
{ 'Order' : [
{ 'orderID': '1',
'OrderLines': {
'OrderLine': [
{ 'lineID':'00001', 'quantity':'1', 'cost':'10', 'description':'foo' },
{ 'lineID':'00002', 'quantity':'2', 'cost':'23.42', 'description':'bar' }
]}
}
{ 'orderID': '2',
'OrderLines': {
'OrderLine':
{ 'lineID':'00003', 'quantity':'6', 'cost':'12.99', 'description':'lonely' }
}
}
]}
If you'll notice, the second order only has one OrderLine, so instead of returning a list containing dictionaries, it returns the dictionary. Here is what I am trying to do:
orders_json = json.loads(from_server)
for order in orders_json['Order']:
print 'Order ID: {}'.format(order['orderID'])
for line in order['OrderLines']['OrderLine']:
print '-> Line ID: {}, Quantity: {}'.format(line['lineID'], line['quantity'])
It works just fine for the first order, but the second order throws TypeError: string indices must be integers since line is now a string containing the dictionary, instead of a dictionary from the list. I've been banging my head against this for hours now, and I feel like I am missing something obvious.
Here are some of the things I have tried:
Using len(line) to see if it gave me something unique for the one line orders. It does not. It returns the number of key:value pairs in the dictionary, which in my real program is 10, which an order containing 10 lines would also return.
Using a try/except. Well, that stops the TypeError from halting the whole thing, but I can't figure out how to address the dictionary once I've done that. Line is a string for single line orders instead of a dictionary.
Whoever designed that API did not do a terribly good job. Anyway, you could check whether OrderLine is a list and, if it's not, wrap it in a one-element list before doing any processing:
if not isinstance(order_line, list):
order_line = [order_line]
That would work, my personal preference would be to get the API fixed.
I'd check if the type is correct and then convert it to a list if necessary to have a uniform access:
lines = order['OrderLines']['OrderLine']
lines = [lines] if not isinstance(lines, list) else lines
for line in lines:
...
You can check the type of the object you try to access:
# ...
print 'Order ID: {0}'.format(order['orderID'])
lines = order['OrderLines']['OrderLine']
if isinstance(lines, list):
for line in lines:
print line['lineID']
elif isinstance(lines, dict):
print lines['lineID']
else:
raise ValueError('Illegal JSON object')
Edit: Wrapping the dict in a list as proposed by #NPE is the nicer and smarter solution.

Categories