JSON move child keys up one level - python

I have a Python script that parses a JSON file like below:
[
{
"_index": "bulletins",
"_type": "bulletin",
"_id": "OPENWRT-SA-000001",
"_score": null,
"_source": {
"lastseen": "2016-09-26T15:45:23",
"references": [
"http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-3193",
],
"affectedPackage": [
{
"OS": "OpenWrt",
"OSVersion": "15.05",
"packageVersion": "9.9.8-P3-1",
"packageFilename": "UNKNOWN",
"arch": "all",
"packageName": "bind",
"operator": "lt"
}
],
"edition": 1,
"description": "value in here,
"reporter": "OpenWrt Project",
"published": "2016-01-24T13:33:41",
"title": "bind: Security update (4 CVEs)",
"type": "openwrt",
"bulletinFamily": "unix",
"cvelist": [
"CVE-2015-8704",
],
"modified": "2016-01-24T13:33:41",
"id": "OPENWRT-SA-000001",
"href": "https://lists.openwrt.org/pipermail/openwrt-security-announce/2016-January/000001.html",
"cvss": {
"score": 7.1,
"vector": "AV:NETWORK/AC:MEDIUM/Au:NONE/C:NONE/I:NONE/A:COMPLETE/"
}
},
"sort": [
34872
]
},
I have removed some of the values to keep the post shorter but leaving some in to try to keep the structure.
I want to take all sub keys from the _source key and move them up to the same level as _source and then delete the _source key.
My code to parse the JSON is:
import json
import logging
import logging.handlers
import os
import pymongo
from pymongo import MongoClient
def import_json(mongo_server,mongo_port, vuln_folder):
try:
logging.info('Connecting to MongoDB')
client = MongoClient(mongo_server, mongo_port)
db = client['vuln_sets']
coll = db['vulnerabilities']
logging.info('Connected to MongoDB')
basepath = os.path.dirname(__file__)
filepath = os.path.abspath(os.path.join(basepath, ".."))
archive_filepath = filepath + vuln_folder
filedir = os.chdir(archive_filepath)
file_count = 0
for item in os.listdir(filedir):
if item.endswith('.json'):
file_name = os.path.abspath(item)
with open(item, 'r') as currentfile:
vuln_counter = 0
duplicate_count = 0
logging.info('Currently processing ' + item)
file_count +=1
json_data = currentfile.read()
vuln_content = json.loads(json_data)
for vuln in vuln_content:
try:
del vuln['_type']
coll.insert(vuln, continue_on_error=True)
vuln_counter +=1
except pymongo.errors.DuplicateKeyError:
duplicate_count +=1
logging.info('Added ' + str(vuln_counter) + ' vulnerabilities for ' + item)
logging.info('Found ' + str(duplicate_count) + ' duplicate records!')
os.remove(file_name)
logging.info('Processed ' + str(file_count) + ' files')
except Exception as e:
logging.exception(e)
Which you can see already deletes one key that is not needed but that key has no needed data where as I need the sub keys from _source. I am not sure on the best way to achieve this, whether it would be programmatically correct to just re-create the JSON file with the new info but I need to keep the order of the keys and structure apart from moving the sub keys up one level.

You can use the dictionary update() function to achieve what you're trying to do, but it's important to note that dictionaries don't have an "order of the keys" - see: Key Order in Python Dictionaries.
Here's an example of one way to do this, starting with a dictionary definition.
d = {
"_index": "bulletins",
"_type": "bulletin",
"_id": "OPENWRT-SA-000001",
"_score": None,
"_source": {
"lastseen": "2016-09-26T15:45:23",
"references": [
"http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-3193",
],
"affectedPackage": [
{
"OS": "OpenWrt",
"OSVersion": "15.05",
"packageVersion": "9.9.8-P3-1",
"packageFilename": "UNKNOWN",
"arch": "all",
"packageName": "bind",
"operator": "lt"
}
],
"edition": 1,
"description": "value in here",
"reporter": "OpenWrt Project",
"published": "2016-01-24T13:33:41",
"title": "bind: Security update (4 CVEs)",
"type": "openwrt",
"bulletinFamily": "unix",
"cvelist": [
"CVE-2015-8704",
],
"modified": "2016-01-24T13:33:41",
"id": "OPENWRT-SA-000001",
"href": "https://lists.openwrt.org/pipermail/openwrt-security-announce/2016-January/000001.html",
"cvss": {
"score": 7.1,
"vector": "AV:NETWORK/AC:MEDIUM/Au:NONE/C:NONE/I:NONE/A:COMPLETE/"
}
}
}
# create a new dictionary with everything except the key "_source"
new_d = {key: d[key] for key in d if key != '_source'}
# add the keys/values from "_source" to new dictionary
new_d.update(d['_source']) # This will overwriting any existing keys
The output of new_d:
{'_id': 'OPENWRT-SA-000001',
'_index': 'bulletins',
'_score': None,
'_type': 'bulletin',
'affectedPackage': [{'OS': 'OpenWrt',
'OSVersion': '15.05',
'arch': 'all',
'operator': 'lt',
'packageFilename': 'UNKNOWN',
'packageName': 'bind',
'packageVersion': '9.9.8-P3-1'}],
'bulletinFamily': 'unix',
'cvelist': ['CVE-2015-8704'],
'cvss': {
'score': 7.1,
'vector': 'AV:NETWORK/AC:MEDIUM/Au:NONE/C:NONE/I:NONE/A:COMPLETE/'},
'description': 'value in here',
'edition': 1,
'href': 'https://lists.openwrt.org/pipermail/openwrt-security-announce/2016-January/000001.html',
'id': 'OPENWRT-SA-000001',
'lastseen': '2016-09-26T15:45:23',
'modified': '2016-01-24T13:33:41',
'published': '2016-01-24T13:33:41',
'references': ['http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-
3193'],
'reporter': 'OpenWrt Project',
'title': 'bind: Security update (4 CVEs)',
'type': 'openwrt'}

I managed to get it working by using the following code:
for vuln in vuln_content:
try:
del vuln['_type']
new_vuln = {key: vuln[key] for key in vuln if key != '_source'}
new_vuln.update(vuln['_source'])
coll.insert(new_vuln, continue_on_error=True)
vuln_counter +=1
except pymongo.errors.DuplicateKeyError:
duplicate_count +=1

Related

How to get the values of dictionary python?

I have the below python dictionary stored as dictPython
{
"paging": {"count": 10, "start": 0, "links": []},
"elements": [
{
"organizationalTarget~": {
"vanityName": "vv",
"localizedName": "ViV",
"name": {
"localized": {"en_US": "ViV"},
"preferredLocale": {"country": "US", "language": "en"},
},
"primaryOrganizationType": "NONE",
"locations": [],
"id": 109,
},
"role": "ADMINISTRATOR",
},
],
}
I need to get the values of vanityName, localizedName and also the values from name->localized and name->preferredLocale.
I tried dictPython.keys() and it returned dict_keys(['paging', 'elements']).
Also I tried dictPython.values() and it returned me what is inside of the parenthesis({}).
I need to get [vv, ViV, ViV, US, en]
I am writing this in a form of answer, so I can get to explain it better without the comments characters limit
a dict in python is an efficient key/value structure or data type
for example dict_ = {'key1': 'val1', 'key2': 'val2'} to fetch key1 we can do it in 2 different ways
dict_.get(key1) this returns the value of the key in this case val1, this method has its advantage, that if the key1 is wrong or not found it returns None so no exceptions are raised. You can do dict_.get(key1, 'returning this string if the key is not found')
dict_['key1'] doing the same .get(...) but will raise a KeyError if the key is not found
So to answer your question after this introduction,
a dict can be thought of as nested dictionaries and/or objects inside of one another
to get your values you can do the following
# Fetch base dictionary to make code more readable
base_dict = dict_["elements"][0]["organizationalTarget~"]
# fetch name_dict following the same approach as above code
name_dict = base_dict["name"]
localized_dict = name_dict["localized"]
preferred_locale_dict = name_dict ["preferredLocale"]
so now we fetch all of the wanted data in their corresponding locations from your given dictionary, now to print the results, we can do the following
results_arr = []
for key1, key2 in zip(localized_dict, preferredLocale_dict):
results_arr.append(localized_dict.get(key1))
results_arr.append(preferred_locale_dict.get(key2))
print(results_arr)
What about:
dic = {
"paging": {"count": 10, "start": 0, "links": []},
"elements": [
{
"organizationalTarget~": {
"vanityName": "vv",
"localizedName": "ViV",
"name": {
"localized": {"en_US": "ViV"},
"preferredLocale": {"country": "US", "language": "en"},
},
"primaryOrganizationType": "NONE",
"locations": [],
"id": 109,
},
"role": "ADMINISTRATOR",
},
],
}
base = dic["elements"][0]["organizationalTarget~"]
c = base["name"]["localized"]
d = base["name"]["preferredLocale"]
output = [base["vanityName"], base["localizedName"]]
output.extend([c[key] for key in c])
output.extend([d[key] for key in d])
print(output)
outputs:
['vv', 'ViV', 'ViV', 'US', 'en']
So something like this?
[[x['organizationalTarget~']['vanityName'],
x['organizationalTarget~']['localizedName'],
x['organizationalTarget~']['name']['localized']['en_US'],
x['organizationalTarget~']['name']['preferredLocale']['country'],
x['organizationalTarget~']['name']['preferredLocale']['language'],
] for x in s['elements']]

How to convert a list of OrderedDict to nested json with grouped keys in python

I'm working on a project where I need to convert a set of data rows from database into list of OrderedDict for other purpose and use this list of OrderedDict to convert into a nested JSON format in python. I'm starting to learn python. I was able convert the query response from database which is a list of lists to list of OrderedDict.
I have the list of OrderedDict as below:
{
'OUTBOUND': [
OrderedDict([('Leg', 1), ('SessionID', 'W12231fwfegwcaa2'),('FeeCode', 'ATO'),('SeatGroup', '2'),
('Currency', 'MXN'),('Modality', 'VB'),('BookingClass', 'A'),('Price', 145.0),('Num_Pax', 1),('Channel', 'Web')]),
OrderedDict([('Leg', 1),('SessionID', 'W12231fwfegwcaa2'),('FeeCode', 'ATO'),('SeatGroup', '4'),
('Currency', 'MXN'),('Modality', 'VB'),('BookingClass', 'A'),('Price', 111.0),('Num_Pax', 1),('Channel', 'Web')]),
OrderedDict([('Leg', 1),('SessionID', 'W12231fwfegwcaa2'),('FeeCode', 'BDM'),('SeatGroup', 'null'),
('Currency', 'MXN'),('Modality', 'VB'),('BookingClass', 'A'),('Price', 111.0),('Num_Pax', 1),('Channel', 'Web')]),
OrderedDict([('Leg', 2),('SessionID', 'W12231fwfegwcaa2'),('FeeCode', 'ATO'),('SeatGroup', '1'),
('Currency', 'MXN'),('Modality', 'VB'),('BookingClass', 'U'),('Price', 180.0),('Num_Pax', 1),('Channel', 'Web'))]),
OrderedDict([('Leg', 2),('SessionID', 'W12231fwfegwcaa2'),('FeeCode', 'ATO'),('SeatGroup', '4'),
('Currency', 'MXN'),('Modality', 'VB'),('BookingClass', 'U'),('Price', 97.0),('Num_Pax', 1),('Channel', 'Web')]),
OrderedDict([('Leg', 2),('SessionID', 'W12231fwfegwcaa2'),('FeeCode', 'BDM'),('SeatGroup', 'null'),
('Currency', 'MXN'),('Modality', 'VB'),('BookingClass', 'U'),('Price', 97.0),('Num_Pax', 1),('Channel', 'Web')])
]
}
And I needed the nested format like below:
{
"OUTBOUND": [
{
"Leg": 1,
"SessionID": "W12231fwfegwcaa2",
"Modality": "VB",
"BookingClass": "A",
"FeeCodes":[
{
"FeeCode": "ATO",
"Prices":
[
{
"SeatGroup": "2",
"Price": 145.0,
"Currency": "MXN"
},
{
"SeatGroup": "4",
"Price": 111.0,
"Currency": "MXN"
}
]
},
{
"FeeCode": "VBABDM",
"Prices":
[
{
"SeatGroup": "null",
"Price": 111.0,
"Currency": "MXN"
}
]
}
],
"Num_Pax": 1,
"Channel": "Web"
},
{
"Leg": 2,
"SessionID": "W12231fwfegwcaa2",
"Modality": "VB",
"BookingClass": "U",
"FeeCodes":[
{
"FeeCode": "ATO",
"Prices":
[
{
"SeatGroup": "1",
"Price": 180.0,
"Currency": "MXN"
},
{
"SeatGroup": "4",
"price": 97.0,
"Currency": "MXN"
}
]
},
{
"FeeCode": "VBABDM",
"Prices":
[
{
"SeatGroup": "null",
"price": 97.0,
"Currency": "MXN"
}
]
}
],
"Num_Pax": 1,
"Channel": "Web"
}
]
}
If I'm not wrong, I need to group by Leg, SessionID, Modality, BookingClass, NumPax and Channel and group the FeeCode, SeatGroup, Price and Currency into nested format as above but unable to move ahead with how to loop and group for nesting.
It would be great if I could get some help. Thanks
I was able to write a python code to get the format as I needed using simple looping with a couple of changes in the output like the fields SessionID, Num_Pax and Channel is taken outside then the OUTBOUND field and fields within are generated.
Instead of OrderedDict, I used a list of lists as input which I convert into Pandas DataFrame and work with the DataFrame to get the nested format.
Below is the code I used:
outbound_df = pd.DataFrame(response_outbound,columns=All_columns)
Common_columns = ['Leg', 'Modality', 'BookingClass']
### Taking SessionID, AirlineCode,Num_Pax and Channel outside OUTBOUND part as they are common for all the leg level data
response_data['SessionID'] = outbound_df['SessionID'].unique()[0]
response_data['Num_Pax'] = int(outbound_df['Num_Pax'].unique()[0])
response_data['Channel'] = outbound_df['Channel'].unique()[0]
temp_data = []
Legs = outbound_df['Leg'].unique()
for i in Legs:
subdata = outbound_df[outbound_df['Leg']==i]
### Initializing leg_data dict
leg_data = collections.OrderedDict()
### Populating common fields of the leg (Leg, Modality,BookingClass)
for j in Common_columns:
if(j=='Leg'):
leg_data[j] = int(subdata[j].unique()[0])
else:
leg_data[j] = subdata[j].unique()[0]
leg_data['FeeCodes'] = []
FeeCodes = subdata['FeeCode'].unique()
for fc in FeeCodes:
subdata_fees = subdata[subdata['FeeCode']==fc]
Prices = {'FeeCode':fc, "Prices":[]}
for _,rows in subdata_fees.iterrows():
data = {}
data['SeatGroup'] = rows['SeatGroup']
data['Price'] = float(rows['Price'])
data['Currency'] = rows['Currency']
Prices["Prices"].append(data)
leg_data["FeeCodes"].append(Prices)
temp_data.append(leg_data)
response_data["OUTBOUND"] = temp_data
I can just do json.dumps on response_data to get json format which will be sent to the next steps.
Below is the output format I get:
{
"SessionID":"W12231fwfegwcaa2",
"Num_Pax":1,
"Channel":"Web",
"OUTBOUND":[
{
"Leg":1,
"Modality":"VB",
"BookingClass":"A",
"FeeCodes":[
{
"FeeCode":"ATO",
"Prices":[
{
"SeatGroup":"2",
"Price":145.0,
"Currency":"MXN"
},
{
"SeatGroup":"4",
"Price":111.0,
"Currency":"MXN"
}
]
},
{
"FeeCode":"VBABDM",
"Prices":[
{
"SeatGroup":"null",
"Price":111.0,
"Currency":"MXN"
}
]
}
]
},
{
"Leg":2,
"Modality":"VB",
"BookingClass":"U",
"FeeCodes":[
{
"FeeCode":"ATO",
"Prices":[
{
"SeatGroup":"1",
"Price":180.0,
"Currency":"MXN"
},
{
"SeatGroup":"4",
"price":97.0,
"Currency":"MXN"
}
]
},
{
"FeeCode":"VBABDM",
"Prices":[
{
"SeatGroup":"null",
"price":97.0,
"Currency":"MXN"
}
]
}
]
}
]
}
Please let me know if we can shorten the code in terms of lengthy iterations or any other changes. Thanks.
PS: Sorry for my editing mistakes
Assuming that you stored the dictionary to some variable foo, you can do:
import json
json.dumps(foo)
And be careful, you added extra bracket in the 4th element OUTBOUND list

how to create a dictionary with list of dictionaries as values from a list of dictionaries

I have this sample list of dictionaries:
[
{
"name": "like father",
"director": "Ajun kun",
"edited": "2014-12-20T21:23:49.867000Z",
"similar_movies": [
"http://movies.dev/api/films/1/",
"http://movies.dev/api/films/3/",
],
"rating": "2.0",
},
{
"name": "be like her",
"director": tuned ku",
"edited": "2014-12-20T21:23:49.870000Z",
"similar_movies": [
"http://movies.dev/api/films/1/"
]
}, .......
]
Some of the dictionaries in the list contain ratings while others do not. I want to generate a new dictionary of like the dictionary below sorted by the ratings:
{
"movies":[
{"name": "movie_4", "rating" : 0.1},
{"name": "movie_1", "rating" : 0.3},
{"name": "movies_5", "rating" : 0.5}
],
"movies_without_rating": [
{"name": "movie_8"},
{"name": "movie_3"}
]
}
Here is my sample code:
from flask import Flask, jsonify, request
import requests
from collections import ChainMap
app = Flask(__name__)
#app.route('/movies', methods=['GET'])
def returnAll():
#note: the URL is just a demo url
response = requests.get("https://movies.dev/api/movies/")
results = response.json()['results']
general_dic = {}
for result in result:
for key, val in result:
if (key == 'rating'):
general_dic['movies']
else:
general_dic['movies_with_rating']
return general_dic
return jsonify(results)
if __name__ == "__main__":
app.run(debug=True)
I got stuck and I couldn't continue, I will greatly appreciate your help.
You can use this example to integrate in your code:
lst = [
{
"movies": "like father",
"rating": "2.0",
},
{
"movies": "other movie",
"rating": "2.5",
},
{
"movies": "be like her",
},
{
"movies": "other movie 2",
"rating": "5.5",
},
{
"movies": "other movie 3",
},
]
out = {'movies':[], 'movies_without_rating':[]}
for movie in lst:
if 'rating' in movie:
out['movies'].append({'name': movie['movies'], 'rating': float(movie['rating'])})
else:
out['movies_without_rating'].append({'name': movie['movies']})
# sort it
out['movies'] = sorted(out['movies'], key=lambda k: k['rating'])
# pretty print on screen:
from pprint import pprint
pprint(out)
Prints:
{'movies': [{'name': 'like father', 'rating': 2.0},
{'name': 'other movie', 'rating': 2.5},
{'name': 'other movie 2', 'rating': 5.5}],
'movies_without_rating': [{'name': 'be like her'}, {'name': 'other movie 3'}]}
It seems something like this is what you'd like:
def separate_movies(movies_list):
movies_with_rating = []
movies_without_rating = []
for movie in movies_list:
name = movie["movies"]
if "rating" in movie:
movies_with_rating.append({
"name": name,
"rating": movie["rating"]
})
else:
movies_without_rating.append({
"name": name
})
movies_with_rating.sort(key = lambda movie: movie["rating"])
return {
"movies": movies_with_rating,
"movies_without_rating": movies_without_rating
}
The key here is using the in keyword to check whether a movie has a rating.

Delete a specific character in a list in Python

I have a list that has a couple of dicts inside and they are all separated with a comma ",". What is happening is that when i create this list i am adding , inside a for loop, a comma after every dict to separate them but it is also adding a last comma after the last dictionary. Something like:
"guests": [{
"age": "18",
"birthDate": null,
"emailAddress": null,...
....
"name": {
"prefix": "Mr.",
"firstName": "James",
"middleName": "",
"lastName": "Jones",
"suffix": ""
}
},----------------------------->This comma
]
I think that last comma is creating some issues when trying to make a post request to the web service. So, How can i delete just that last comma inside the list?
Thanks
Edit
The creation of the list is happening inside a for loop. Something like:
participants_body = ''
for guest in guests_info:
post_body = '{"profile": {"name": {"title": "' + guest["title"] + '","firstName": "' \
+ guest["first_name"] + '","lastName": "' + guest["last_name"] \
+ '"},"age": 18},"preferences": {"avatarIdentifier": "15655408","favoriteCharacterIdentifier":' \
' "15655408"},"friendsAndFamily": {"groupClassification": {"name": "TRAVELLING_PARTY"},' \
'"accessClassification": {"name": "PLAN_VIEW_SHARED"}}}'
response = requests.post(url, data=post_body, headers=headers)
json_response = response.json()
participants_body = '{"age": "' + str(json_response["profile"]["age"]) + '","birthDate": null,"emailAddress": null,' \
'"phone": null,"primary": false,"swid": null,"guid": "' + guid + '","gender": null,"type": null,' \
'"participantId": "' + p_id + '","profileLink": "https://env5.nge.api.go.com' + profileLink + '", ' \
'"infantSittingWithAdult": false,"avatar": null,"itemsAssigned": ' \
'["' + item_id + '"],"address": null,"phoneNumber": null,"dataType": "basic",' \
'"isRoomAssigned": true,"isVacationOfferAssigned": true,"ageGroup": "","name": {' \
'"prefix": "' + json_response["profile"]["name"]["title"] + '","firstName": "' \
+ json_response["profile"]["name"]["firstName"] + '","middleName": "","lastName": "' \
+
json_response["profile"]["name"]["lastName"] + '","suffix": ""}},'------------> HERE IS THE COMA
post_body_participants += participants_body
So, that´s why i´m getting the coma. I just need to delete it after the for loop
EDIT
I´m creating a Post message and i´m getting this error:
{u'errors': [{u'message': u'org.codehaus.jackson.map.JsonMappingException: Can not instantiate value of type [simple type, class com.disney.wdpro.service.booking.webservice.resource.ParticipantWithAssignmentResourceCollection] from JSON String; no single-String constructor/factory method'}]}
I read a couple of SO questions and they mentioned that maybe this is happening because an error with the json format.
Also i can see how the body of the post is created in other messages in the logs and that last comma is not there, so maybe that´s what´s happening
I'm not sure why you're creating this as a string. You'll be happier to create the dicts as dicts. The code is much more readable, which will help you when you have to change it later. Besides that, it will eliminate little typo bugs like you're experiencing.
post_body = {
'profile': {
'name': {
'title': guest['title'],
'firstName': guest['first_name'],
'lastName': guest['last_name'] },
'age': 18 },
'preferences': {
'avatarIdentifier': 15655408,
'favoriteCharacterIdentifier': 15655408 },
'friendsAndFamily': {
'groupClassification': {
'name': 'TRAVELLING_PARTY' },
'accessClassification': {
'name': 'PLAN_VIEW_SHARED' }
}
}
It's easy to turn that dict into a JSON string:
import json
post_body = json.dumps(post_body)
You can do the same thing with creating a list from the participants_body response. Just create the one dict as above, and append it with post_body_participants.append(participants_body). Again, you can access that list in the form of a JSON string with json.dumps(post_body_participants).
You will save yourself a great deal of pain if you use the built in json encoders/decoders to build your json strings. Building them by hand is error prone. Why not stand on the shoulders of giants?
import requests
import json
participants =[]
for guest in guests_info:
#Build Python objects and not json strings
#Convert it all to json later
post_body = {
'profile': {
'name': {
'title': guest['title'],
'firstName': guest['first_name'],
'lastName': guest['last_name'] },
'age': 18 },
'preferences': {
'avatarIdentifier': 15655408,
'favoriteCharacterIdentifier': 15655408 },
'friendsAndFamily': {
'groupClassification': {
'name': 'TRAVELLING_PARTY' },
'accessClassification': {
'name': 'PLAN_VIEW_SHARED' }
}
}
#The requests module has json encoding/decoding built in
response = requests.post(url, json=post_body, headers=headers)
#Or you could use Python's built in json module
#response = requests.post(url, data=json.dumps(post_body), headers=headers)
json_response = response.json() #This decodes the json string in the response to a Python object
participant = {
"age": json_response["profile"]["age"],
"birthDate": None,
"emailAddress": None,
"phone": None,
"primary": False,
"swid": None,
"guid": guid,
"gender": None,
"type": None,
"participantId": p_id,
"profileLink": "https://env5.nge.api.go.com" + profileLink + ,
"infantSittingWithAdult": False,
"avatar": None,
"itemsAssigned": [item_id],
"address": None,
"phoneNumber": None,
"dataType": "basic",
"isRoomAssigned": True,
"isVacationOfferAssigned": True,
"ageGroup": "",
"name": {
"prefix": json_response["profile"]["name"]["title"],
"firstName": json_response["profile"]["name"]["firstName"],
"middleName": "",
"lastName": json_response["profile"]["name"]["lastName"],
"suffix": ""}
}
}
participants.append(participant)

Grab element from json dump

I'm using the following python code to connect to a jsonrpc server and nick some song information. However, I can't work out how to get the current title in to a variable to print elsewhere. Here is the code:
TracksInfo = []
for song in playingSongs:
data = { "id":1,
"method":"slim.request",
"params":[ "",
["songinfo",0,100, "track_id:%s" % song, "tags:GPASIediqtymkovrfijnCYXRTIuwxN"]
]
}
params = json.dumps(data, sort_keys=True, indent=4)
conn.request("POST", "/jsonrpc.js", params)
httpResponse = conn.getresponse()
data = httpResponse.read()
responce = json.loads(data)
print json.dumps(responce, sort_keys=True, indent=4)
TrackInfo = responce['result']["songinfo_loop"][0]
TracksInfo.append(TrackInfo)
This brings me back the data in json format and the print json.dump brings back:
pi#raspberrypi ~/pithon $ sudo python tom3.py
{
"id": 1,
"method": "slim.request",
"params": [
"",
[
"songinfo",
"0",
100,
"track_id:-140501481178464",
"tags:GPASIediqtymkovrfijnCYXRTIuwxN"
]
],
"result": {
"songinfo_loop": [
{
"id": "-140501481178464"
},
{
"title": "Witchcraft"
},
{
"artist": "Pendulum"
},
{
"duration": "253"
},
{
"tracknum": "1"
},
{
"type": "Ogg Vorbis (Spotify)"
},
{
"bitrate": "320k VBR"
},
{
"coverart": "0"
},
{
"url": "spotify:track:2A7ZZ1tjaluKYMlT3ItSfN"
},
{
"remote": 1
}
]
}
}
What i'm trying to get is result.songinfoloop.title (but I tried that!)
The songinfo_loop structure is.. peculiar. It is a list of dictionaries each with just one key.
Loop through it until you have one with a title:
TrackInfo = next(d['title'] for d in responce['result']["songinfo_loop"] if 'title' in d)
TracksInfo.append(TrackInfo)
A better option would be to 'collapse' all those dictionaries into one:
songinfo = reduce(lambda d, p: d.update(p) or d,
responce['result']["songinfo_loop"], {})
TracksInfo.append(songinfo['title'])
songinfo_loop is a list not a dict. That means you need to call it by position, or loop through it and find the dict with a key value of "title"
positional:
responce["result"]["songinfo_loop"][1]["title"]
loop:
for info in responce["result"]["songinfo_loop"]:
if "title" in info.keys():
print info["title"]
break
else:
print "no song title found"
Really, it seems like you would want to have the songinfo_loop be a dict, not a list. But if you need to leave it as a list, this is how you would pull the title.
The result is really a standard python dict, so you can use
responce["result"]["songinfoloop"]["title"]
which should work

Categories