I have created a var that is equal to t.json. The JSON file is a follows:
{
"groups": {
"customerduy": {
"nonprod": {
"name": "customerduynonprod",
"id": "529646781943",
"owner": "cloudops#coerce.com",
"manager_email": ""
},
"prod": {
"name": "phishing_duyaccountprod",
"id": "241683454720",
"owner": "cloudops#coerce.com",
"manager_email": ""
}
},
"customerduyprod": {
"nonprod": {
"name": "phishing_duyaccountnonprod",
"id": "638968214142",
"owner": "cloudops#coerce.com",
"manager_email": ""
}
},
"ciasuppliergenius": {
"prod": {
"name": "ciasuppliergeniusprod",
"id": "220753788760",
"owner": "cia_developers#coerce.com",
"manager_email": "jarks#coerce.com"
}
}
}
}
my goal was to pars this JSON file and get value for "owner" and output it to a new var. Example below:
t.json = group_map
group_id_aws = group(
group.upper(),
"accounts",
template,
owner = group_map['groups']['prod'],
manager_description = "Groups for teams to access their product accounts.",
The error I keep getting is: KeyError: 'prod'
Owner occurs 4 times, so here is how to get all of them.
import json
# read the json
with open("C:\\test\\test.json") as f:
data = json.load(f)
# get all 4 occurances
owner_1 = data['groups']['customerduy']['nonprod']['owner']
owner_2 = data['groups']['customerduy']['prod']['owner']
owner_3 = data['groups']['customerduyprod']['nonprod']['owner']
owner_4 = data['groups']['ciasuppliergenius']['prod']['owner']
# print results
print(owner_1)
print(owner_2)
print(owner_3)
print(owner_4)
the result:
cloudops#coerce.com
cloudops#coerce.com
cloudops#coerce.com
cia_developers#coerce.com
You get a key error since the key 'prod' is not in 'groups'
What you have is
group_map['groups']['customerduy']['prod']
group_map['groups']['ciasuppliergenius']['prod']
So you will have to extract the 'owner' from each element in the tree:
def s(d,t):
for k,v in d.items():
if t == k:
yield v
try:
for i in s(v,t):
yield i
except:
pass
print(','.join(s(j,'owner')))
If your JSON is loaded in variable data, you can use a recursive function
that deals with the two containers types (dict and list) that can occur
in a JSON file, recursively:
def find_all_values_for_key(d, key, result):
if isinstance(d, dict):
if key in d:
result.append(d[key])
return
for k, v in d.items():
find_all_values_for_key(v, key, result)
elif isinstance(d, list):
for elem in d:
find_all_values_for_key(elem, key, result)
owners = []
find_all_values_for_key(data, 'owner', owners)
print(f'{owners=}')
which gives:
owners=['cloudops#coerce.com', 'cloudops#coerce.com', 'cloudops#coerce.com', 'cia_developers#coerce.com']
This way you don't have to bother with the names of intermediate keys, or in general the structure of your JSON file.
You don't have any lists in your example, but it is trivial to recurse through
them to any dict with an owner key that might "lurk" somewhere nested
under a a list element, so it is better to deal with potential future changes
to the JSON.
Related
I need to get the name information, inside the "object" list.
In this example I need this information (10.0.0.19)
"sourceNetworks":{
"objects":[
{
"type":"Host",
"overridable":false,
"id":"005056BF-7C6E-0ed3-0000-012884911113",
"name":"**10.0.0.19**"
}
]
}
I can get any information that is not in the "objects" lists with the command example_json[['metadata']['accessPolicy']['name']
and I get the "mb-test-01" information correctly from the json, but I don't know the syntax to get the items inside the "object" list.
to create this json I use in GET request this way
example_json = requests.get(f"https://{hostname}/api/fmc_config/v1/domain/{uuid}/policy/accesspolicies/{acp_id}/accessrules?expanded=true",headers=header_acp, verify=False).json()
follow the full json.
{
"metadata":{
"ruleIndex":1,
"section":"Mandatory",
"category":"--Undefined--",
"accessPolicy":{
"type":"AccessPolicy",
"name":"mb-test-01",
"id":"005056BF-7C6E-0ed3-0000-012884914323"
},
"timestamp":1635219651530,
"domain":{
"name":"Global",
"id":"e276abec-e0f2-11e3-8169-6d9ed49b625f",
"type":"Domain"
}
},
"links":{
"self":"https://fmcrestapisandbox.cisco.com/api/fmc_config/v1/domain/e276abec-e0f2-11e3-8169-6d9ed49b625f/policy/accesspolicies/005056BF-7C6E-0ed3-0000-012884914323/accessrules/005056BF-7C6E-0ed3-0000-000268434442"
},
"enabled":true,
"action":"ALLOW",
"type":"AccessRule",
"id":"005056BF-7C6E-0ed3-0000-000268434442",
"sourceNetworks":{
"objects":[
{
"type":"Host",
"overridable":false,
"id":"005056BF-7C6E-0ed3-0000-012884911113",
"name":"10.0.0.19"
}
]
},
"destinationNetworks":{
"objects":[
{
"type":"Host",
"overridable":false,
"id":"005056BF-7C6E-0ed3-0000-012884911491",
"name":"192.168.0.39"
}
]
},
"logBegin":false,
"logEnd":false,
"variableSet":{
"name":"Default-Set",
"id":"76fa83ea-c972-11e2-8be8-8e45bb1343c0",
"type":"VariableSet"
},
"logFiles":false,
"enableSyslog":false,
"vlanTags":{
},
"sendEventsToFMC":false,
"name":"rule-1"
}
Presumably you want to retrieve all "name"s under "objects" keys so you could use a recursive function:
def get_name(d):
for k,v in d.items():
if k=='objects':
for i in v:
yield i.get('name')
elif isinstance(v, dict):
yield from get_name(v)
names = list(get_name(data))
Output:
['10.0.0.19', '192.168.0.39']
I am trying to update transaction ID from the following json:
{
"locationId": "5115",
"transactions": [
{
"transactionId": "1603804404-5650",
"source": "WEB"
} ]
I have done following code for the same, but it does not update the transaction id, but it inserts the transaction id to the end of block:-
try:
session = requests.Session()
with open(
"sales.json",
"r") as read_file:
payload = json.load(read_file)
payload["transactionId"] = random.randint(0, 5)
with open(
"sales.json",
"w") as read_file:
json.dump(payload, read_file)
Output:-
{
"locationId": "5115",
"transactions": [
{
"transactionId": "1603804404-5650",
"source": "WEB"
} ]
}
'transactionId': 1
}
Expected Outut:-
{
"locationId": "5115",
"transactions": [
{
"transactionId": "1",
"source": "WEB"
} ]
This would do it, but only in your specific case:
payload["transactions"][0]["transactionId"] = xxx
There should be error handling for cases like "transactions" key is not int the dict, or there are no records or there are more than one
also, you will need to assign =str(your_random_number) not the int if you wish to have the record of type string as the desired output suggests
If you just want to find the transactionId key and you don't know exactly where it may exist. You can do-
from collections.abc import Mapping
def update_key(key, new_value, jsondict):
new_dict = {}
for k, v in jsondict.items():
if isinstance(v, Mapping):
# Recursive traverse if value is a dict
new_dict[k] = update_key(key, new_value, v)
elif isinstance(v, list):
# Traverse through all values of list
# Recursively traverse if an element is a dict
new_dict[k] = [update_key(key, new_value, innerv) if isinstance(innerv, Mapping) else innerv for innerv in v]
elif k == key:
# This is the key to replace with new value
new_dict[k] = new_value
else:
# Just a regular value, assign to new dict
new_dict[k] = v
return new_dict
Given a dict-
{
"locationId": "5115",
"transactions": [
{
"transactionId": "1603804404-5650",
"source": "WEB"
} ]
}
You can do-
>>> update_key('transactionId', 5, d)
{'locationId': '5115', 'transactions': [{'transactionId': 5, 'source': 'WEB'}]}
Yes because transactionId is inside transactions node. So your code should be like:
payload["transactions"][0].transactionId = random.randint(0, 5)
or
payload["transactions"][0]["transactionId"] = random.randint(0, 5)
I have a dictionary which contains the following json elements.
myjsonDictionary = \
{
"Teams": {
"TeamA": {
"#oid": "123.0.0.1",
"dataRequestList": {
"state": {
"#default": "0",
"#oid": "2"
}
},
"TeamSub": {
"#oid": "3",
"dataRequestList": {
"state": {
"#default": "0",
"#oid": "2"
}
}
}
},
# ....many nested layers
}
}
I have the following issue and am currently very confused on how to solve this problem.
I want to be able to parse this dictionary and get the concatenation of the "#oid" value and the respective "#oid" when I request the "key" such as "TeamA" or "TeamSub".
I have a function which takes in the gettheiDLevelConcatoid(myjsonDictionary, key).
I can call this function like this:
gettheiDLevelConcatoid(myjsonDictionary, key) where "key" is like "TeamA"
And the expected output should be "123.0.0.1.2". Note the 2 appended to the 123.0.0.1.
gettheiDLevelConcatoid(myjsonDictionary, key) where "key" is like TeamSub
Output is "123.0.0.1.3.2". Note the "3.2" added to the "123.0.0.1".
My current implementation:
def gettheiDLevelConcatoid(myjsonDictionary, key)
for item in myjsonDictionary:
if (item == key):
#not sure what to do
I am so lost on how to implement a generic method or approach for this.
With recursive traversal for specific keys:
def get_team_idlvel_oid_pair(d, search_key):
for k, v in d.items():
if k.startswith('Team'):
if k == search_key:
return '{}{}.{}'.format(d['#oid'] + '.' if '#oid' in d else '',
v['#oid'], v['dataRequestList']['state']['#oid'])
elif any(k.startswith('Team') for k_ in v):
return get_team_idlvel_oid_pair(v, search_key)
print(get_team_idlvel_oid_pair(myjsonDictionary['Teams'], 'TeamA'))
print(get_team_idlvel_oid_pair(myjsonDictionary['Teams'], 'TeamSub'))
Sample output:
123.0.0.1.2
123.0.0.1.3.2
I have following JSON, returned from a REST service, where I want to generate a unique names for each value by combining parent keys. For example. name+phone+address+city+name , name+phone+address+city+population+skilled+male and so on.
{
"name": "name",
"phone": "343444444",
"address": {
"lat": 23.444,
"lng": 34.3322,
"city":{
"name": "city name",
"population": {
"skilled": {
"male": 2,
"female": 4
},
"uneducated": {
"male": 20,
"femail": 4
}
}
}
},
"email": "email",
"education": "phd"
}
I want to combine all key names starting from the parent of the JSON tree.
Here is what I am doing
class TestJson
def walk_through(self, json_object):
for k, v in json_object.items():
self.x_path = self.x_path + k
if type(v) is dict:
self.walk_through(v)
else:
print(self.x_path)
self.x_path = ""
This code is printing keys but only starting from the current parent node. I want to combine all keys up to root of the json.
If you ignore the name and phone keys, since they are not ancestors of city name or skilled male and the order of keys is not guaranteed, you can recursively build a flattened dict.
def walk_through(json_object):
d = {}
for k, v in json_object.items():
if isinstance(v, dict):
v = walk_through(v)
for vk, vv in v.items():
d["%s+%s" % (k, vk)] = vv
else:
d[k] = v
return d
print(json.dumps(walk_through(json_object), indent=2))
This prints:
{
"address+city+population+skilled+male": 2,
"name": "name",
"address+lng": 34.3322,
"address+city+name": "city name",
"address+lat": 23.444,
"address+city+population+uneducated+male": 20,
"phone": "343444444",
"address+city+population+uneducated+femail": 4,
"education": "phd",
"email": "email",
"address+city+population+skilled+female": 4
}
Note: this ignores lists an will not find dicts inside them.
If you want to print all keys of your python dict you can do the following:
def print_keys(d):
for key, value in d.iteritems():
print key,
if isinstance(value, dict):
print_keys(value)
I have been looking at the answer to the following question here: How can I select deeply nested key:values from dictionary in python
But my issue isn't in finding a single key inside the deeply nested data structure, but all occurences of a particular key.
For example, like if we modify the data structure in the first example in here:
[
"stats":{
"success": true,
"payload": {
"tag": {
"slug": "python",
"name": "Python",
"postCount": 10590,
"virtuals": {
"isFollowing": false
}
},
"metadata": {
"followerCount": 18053,
"postCount": 10590,
"coverImage": {
"id": "1*O3-jbieSsxcQFkrTLp-1zw.gif",
"originalWidth": 550,
"originalHeight": 300
}
}
}
},
"stats": {
"success": true,
"payload": {
"tag": {
"slug": "python",
"name": "Python",
"postCount": 10590,
"virtuals": {
"isFollowing": false
}
},
"metadata": {
"followerCount": 18053,
"postCount": 10590,
"coverImage": {
"id": "1*O3-jbieSsxcQFkrTLp-1zw.gif",
"originalWidth": 550,
"originalHeight": 300
}
}
}
}
]
How would I get every possible occurrences of "metadata" here?
How about something recursive?
def extractVals(obj, key, resList):
if type(obj) == dict:
if key in obj:
resList.append(obj[key])
for k, v in obj.items():
extractVals(v, key, resList)
if type(obj) == list:
for l in obj:
extractVals(l, key, resList)
resultList1 = []
extractVals(dat, 'metadata', resultList1)
print(resultList1)
yields:
[{'coverImage': {'id': '1*O3-jbieSsxcQFkrTLp-1zw.gif',
'originalHeight': 300,
'originalWidth': 550},
'followerCount': 18053,
'postCount': 10590},
{'coverImage': {'id': '1*O3-jbieSsxcQFkrTLp-1zw.gif',
'originalHeight': 300,
'originalWidth': 550},
'followerCount': 18053,
'postCount': 10590}]
I also had to modify your dataset slightly above to be a valid Python structure. true -> True, false -> False, and removed the keys from the top level list.
You can use a custon class like this one:
class DeepDict:
def __init__(self, data):
self.data = data
#classmethod
def _deep_find(cls, data, key, root, response):
if root:
root += "."
if isinstance(data, list):
for i, item in enumerate(data):
cls._deep_find(item, key, root + str(i), response)
elif isinstance(data, dict):
if key in data:
response.append(root + key)
for data_key, value in data.items():
cls._deep_find(value, key, root + data_key, response)
return response
def deep_find(self, key):
""" Returns all ocurrences of `key` with a dottedpath leading to each.
Use `deepget` to retrieve the values for a given ocurrence, or
`get_all` to iterate over the values for each occurrence of the key.
"""
return self._deep_find(self.data, key, root="", response=[])
#classmethod
def _deep_get(cls, data, path):
if not path:
return data
index = path.pop(0)
if index.isdigit():
index = int(index)
return cls._deep_get(data[index], path)
def deep_get(self, path):
if isinstance(path, str):
path = path.split(".")
return self._deep_get(self.data, path)
def get_all(self, key):
for path in self.deep_find(key):
yield self.deep_get(path)
def __getitem__(self, key):
if key.isdigit():
key = int(key)
return self.data[key]
(Note that although I named it "DeepDict" it is actually a generic JSON container that will work with both lists and dicts as outer elements. BTW, the JSON fragment in your question is broken - both "stats": keys should be wrapped in an extra { })
So, these three custom methods can either find you the precise "path" to each occurrence of a key, or, you can use the get_all method to simply get the contents of how many keys with that name are in the structure as an iterator.
With the above class, after fixing your data I did:
data = DeepDict(<data structure above (fixed)>)
list(data.get_all("metadata"))
and got as output:
[{'coverImage': {'id': '1*O3-jbieSsxcQFkrTLp-1zw.gif',
'originalHeight': 300,
'originalWidth': 550},
'followerCount': 18053,
'postCount': 10590},
{'coverImage': {'id': '1*O3-jbieSsxcQFkrTLp-1zw.gif',
'originalHeight': 300,
'originalWidth': 550},
'followerCount': 18053,
'postCount': 10590}]