I believe you probably meant:
from __future__ import print_function
for song in json_object:
# now song is a dictionary
for attribute, value in song.items():
print(attribute, value) # example usage
NB: You could use song.iteritems instead of song.items if in Python 2.
I believe you probably meant:
from __future__ import print_function
for song in json_object:
# now song is a dictionary
for attribute, value in song.items():
print(attribute, value) # example usage
NB: You could use song.iteritems instead of song.items if in Python 2.
Your loading of the JSON data is a little fragile. Instead of:
json_raw= raw.readlines()
json_object = json.loads(json_raw[0])
you should really just do:
json_object = json.load(raw)
You shouldn't think of what you get as a "JSON object". What you have is a list. The list contains two dicts. The dicts contain various key/value pairs, all strings. When you do json_object[0], you're asking for the first dict in the list. When you iterate over that, with for song in json_object[0]:, you iterate over the keys of the dict. Because that's what you get when you iterate over the dict. If you want to access the value associated with the key in that dict, you would use, for example, json_object[0][song].
None of this is specific to JSON. It's just basic Python types, with their basic operations as covered in any tutorial.
python json dict iterate {key: value} are the same - Stack Overflow
Advice on how to iterate through JSON to find the first instance of a key value pair?
How to iterate through JSON object in Python and get KEY? - Stack Overflow
Iterate through a json list and get specific key and value with Python - Stack Overflow
Change your string formats index:
for json_dict in data:
for key,value in json_dict.iteritems():
print("key: {0} | value: {1}".format(key, value))
Or without using index:
for json_dict in data:
for key,value in json_dict.iteritems():
print("key: {} | value: {}".format(key, value))
Also you can using names instead of index:
for json_dict in data:
for key,value in json_dict.iteritems():
print("key: {key} | value: {value}".format(key=key, value=value))
Update: In python3.6 and later, f-string feature added that allow programmers to make formatted string easiest, a f-string work same as template engine that starting by f prefix and string body come after, and variables and other dynamic things must determine between {} signs, same as below:
print(f'key: A | value: {json_dict["A"]}')
>>> key: A | value: X
You don't need to specify an index at all:
for key, value in json_dict.iteritems():
print("key: {} | value: {}".format(key, value))
I have an undesirable JSON object that I can't modify:
{
"programs": [
],
"streams": [
{
"index": 0,
"codec_name": "hevc",
"codec_type": "video"
},
{
"index": 1,
"codec_name": "aac",
"codec_type": "audio"
},
{
"index": 2,
"codec_name": "opus",
"codec_type": "audio"
},
{
"index": 3,
"codec_name": "ac3",
"codec_type": "audio"
},
{
"index": 4,
"codec_name": "ass",
"codec_type": "subtitle"
},
{
"index": 5,
"codec_name": "ttf",
"codec_type": "attachment"
}
]
}
This is psudo json from the very real output of ffprobe -loglevel error -show_entries format:stream=index,stream,codec_type,codec_name -of json FILENAME
I need to get the first codec_name from the lowest index of the codec_type: audio.
In this case, index 1, 2, and 3 are all of codec_type: audio, so the lowest index/first instance would be 1 and my codec_name would be aac.
Any ideas on how to move forward on a problem like this? I can't seem to find any stackoverflow threads with anything similar.
----------------------------
EDIT, solution here: https://www.reddit.com/r/learnpython/comments/16af8zf/comment/jz74hc9/?utm_source=share&utm_medium=web2x&context=3
Thank you u/shiftybyte, u/djshadesuk!!!
EDITED Try something like:
new_data = []
# Extract all the data and map them by name and status
for value in data:
name = value.get("name")
status = value.get("status")
if name in ['blah', 'blah0', 'blah1', 'blah2', 'blah3']:
new_data.append(dict(
name=name,
status=status))
Option 1
# loop through the new data
for data in new_data:
print(data)
# OUTPUT:
{'name': 'blah', 'status': 'ok'}
{'name': 'blah0', 'status': 'ok'}
{'name': 'blah1', 'status': 'ok'}
{'name': 'blah2', 'status': 'ok'}
{'name': 'blah3', 'status': 'ok'}
Option 2
for data in new_data:
for key, value in data.items():
print(key, value)
#OUTPUT:
name blah
status ok
name blah0
status ok
name blah1
status ok
name blah2
status ok
name blah3
status ok
Option 3
for data in new_data:
print(data['name'], data['status'])
#OUTPUT
blah ok
blah0 ok
blah1 ok
blah2 ok
blah3 ok
You don't really want dynamic variables, but you can use a list comprehension. You should also take advantage of constant-cost set membership test:
keep = set(['blah', 'blah0', 'blah1', 'blah2', 'blah3'])
result = [(value['name'], value['status']) for value in data if value['name'] in keep]
print(result)
Output:
[('blah', 'ok'),
('blah0', 'ok'),
('blah1', 'ok'),
('blah2', 'ok'),
('blah3', 'ok')]
If you want a dictionary:
keep = set(['blah', 'blah0', 'blah1', 'blah2', 'blah3'])
result = {value['name']: value['status'] for value in data if value['name'] in keep}
print(result)
I'm trying to restructure JSON output from a API to the specific format that Ansible wants for it's invetory file. To do this I thought I would loop through the JSON and grab the variables I need and then feed that into the proper structure. However, I noticed my API JSON is using the same $ key for multiple variables. How can I properly reference and differentiate between the variables? Here is an example:
"model-responses": {
"model": [
{
"@mh": "0x11e013",
"attribute": [
{
"@id": "0x1006e",
"$": "switch1"
},
{
"@id": "0x23000e",
"$": "Raritan Computer, Inc.DV"
},
{
"@id": "0x12d7f",
"$": "10.10.10.1"
},
{
"@id": "0x10052",
"$": "PX2 030610"
}
]
},
{
"@mh": "0x115014",
"attribute": [
{
"@id": "0x1006e",
"$": "switch2"
},
{
"@id": "0x23000e",
"$": "DCS-7010T-48"
},
{
"@id": "0x12d7f",
"$": "10.10.10.2"
},
{
"@id": "0x10052",
"$": "Arista Networks EOS version 4.22.3M-INT running on an Arista Networks DCS-7010T-48"
}
]
},Let me de-construct your code assuming json is a dictionary with the data {u'key2': u'xyz', u'key1': u'abc'}
test = [{'a': j['key1'], 'token':j['key2']} for j in json ]
What you were actually doing is iterating through the key in the dictionary and then treating the result as a dictionary, this will give you an error!
The j in json in each loop is the key, so in the first iteration you get the result 'key1' and when you try j['key1'] you assumed that j is a dictionary, but in fact it is a string, hence the error TypeError: string indices must be integers.
This is probably what you are looking for to help you with your solution.
This will give you a list of dictionaries:
test = [{key, value} for key, value in json.items()]
The result:
[{u'key2': u'xyz'}, {u'key1': u'abc'}]
The reason your code failed is because you were trying to unnecessarily iterate through the dictionary, but if you wish to disassemble it simply do this:
[dict(a=json['key1'], token=json['key2'])]
Result:
[{'a': u'abc', 'token': u'xyz'}]
I was just looking for a way to make the code a little more fault tolerant and able to handle both single and multiple objects
The easy way to do that is to check the type of data coming in and change it into a standardized form that the rest of your code can consume. If you get a dict just create a list to hold the dict and the rest of the code will work.
json = request.get_json(force=True) # receives request from postman
for j in json:
print str(j)
if isinstance(json, dict):
json = [json]
test = [{'a': j['key1'], 'token':j['key2']} for j in json ]
Test key existence in attributes to retrieve the different values:
df = []
for item in json_response["items"]:
errors = "NA"
if "errors" in item["attributes"]
errors = item["attributes"]["errors"]
elif "RefreshFailure" in item["attributes"]:
errors = item["attributes"]["RefreshFailure"]
df.append({
'AccountName': item["accountName"],
'Action': item["action"],
'Application': item["application"],
'AppID': item["attributes"]["appId"],
'AppName': item["attributes"]["AppName"],
'Errors': errors,
'ContextID': item["contextid"],
'Created': item["created"],
'HostName': item["hostname"],
'EventID': item["id"],
'Info': item["info"],
'ipaddr': item["ipaddr"],
'EventSource': item["source"],
'Stack': item["stack"],
'Target': item["target"],
'TrackingID': item["trackingId"],
'Type': item["type"]
})
I tried to emulate your data to make the code work.
import json
from pprint import pprint
json_data = '''
{
"items": [
{
"accountName": null,
"action": "Disable",
"application": "Application1",
"attributes": {
"appId": "7d264050024",
"AppName": "Application1",
"errors": [
"Rule: Rule not found."
]
},
"contextid": null,
"created": 1553194821098,
"hostname": null,
"id": "ac09ea0082",
"info": null,
"ipaddr": null,
"source": "System1",
"stack": null,
"target": "TargetName1.",
"trackingId": null,
"type": null
},
{
"accountName": null,
"action": "Disable",
"application": "Application1",
"attributes": {
"appId": "7d2451684288",
"cloudAppName": "Application1",
"RefreshFailure": true
},
"contextid": null,
"created": 1553194821098,
"hostname": null,
"id": "ac09ea0082",
"info": null,
"ipaddr": null,
"source": "System1",
"stack": null,
"target": "TargetName1.",
"trackingId": null,
"type": null
}
]
}'''
json_response = json.loads(json_data)
def capitalize(s):
return s[0].upper() + s[1:]
df = []
for item in json_response["items"]:
d = {}
# Iterate over the items in the dictionary/json object and add them one by one using a loop
# This will work even if the items in the json_response changes without having to change the code
for key, value in item.items():
# "attributes" is itself a dictionary/json object
# Its items have to be unpacked and added instead of adding it as a raw object
if isinstance(value, dict):
for k, v in value.items():
d[capitalize(k)] = v
else:
d[capitalize(key)] = value
df.append(d)
pprint(df)
Output:
[{'AccountName': None,
'Action': 'Disable',
'AppId': '7d264050024',
'AppName': 'Application1',
'Application': 'Application1',
'Contextid': None,
'Created': 1553194821098,
'Errors': ['Rule: Rule not found.'],
'Hostname': None,
'Id': 'ac09ea0082',
'Info': None,
'Ipaddr': None,
'Source': 'System1',
'Stack': None,
'Target': 'TargetName1.',
'TrackingId': None,
'Type': None},
{'AccountName': None,
'Action': 'Disable',
'AppId': '7d2451684288',
'Application': 'Application1',
'CloudAppName': 'Application1',
'Contextid': None,
'Created': 1553194821098,
'Hostname': None,
'Id': 'ac09ea0082',
'Info': None,
'Ipaddr': None,
'RefreshFailure': True,
'Source': 'System1',
'Stack': None,
'Target': 'TargetName1.',
'TrackingId': None,
'Type': None}]
If you want the key name to be Errors even when the actual key name is RefreshFailure, you can add these lines of code before df.append(d)
...
if 'RefreshFailure' in d:
d['Errors'] = d['RefreshFailure']
del d['RefreshFailure']
df.append(d)
With these few extra lines of code, the output would look like this:
[{'AccountName': None,
'Action': 'Disable',
'AppId': '7d264050024',
'AppName': 'Application1',
'Application': 'Application1',
'Contextid': None,
'Created': 1553194821098,
'Errors': ['Rule: Rule not found.'],
'Hostname': None,
'Id': 'ac09ea0082',
'Info': None,
'Ipaddr': None,
'Source': 'System1',
'Stack': None,
'Target': 'TargetName1.',
'TrackingId': None,
'Type': None},
{'AccountName': None,
'Action': 'Disable',
'AppId': '7d2451684288',
'Application': 'Application1',
'CloudAppName': 'Application1',
'Contextid': None,
'Created': 1553194821098,
'Errors': True,
'Hostname': None,
'Id': 'ac09ea0082',
'Info': None,
'Ipaddr': None,
'Source': 'System1',
'Stack': None,
'Target': 'TargetName1.',
'TrackingId': None,
'Type': None}]