[英]How to iterate over all keys of a json with nested dictionaries and lists?
我需要修改以下json文件test.json:
{
"install": {
"site": {
"acls": {
"dns": {
"authorized_ports": ["53:tcp", "53:udp"]
}
},
"network": {
"clusters": {
"__ip_range_1__": {
"dhcpstart": "__ip__",
"dhcpend": "__ip__",
"adminip": "__ip__"
},
"__ip_range_2__": {
"dhcpstart": "__ip__",
"dhcpend": "__ip__",
"adminip": "__ip__"
}
}
}
}
}
}
以上是縮寫,原始文件中還有更多條目。 我每個站點都有幾個這樣的文件,因此每個文件的__ip_range_x__
和每個IP都不同。 我需要向每個__ip_range_x__
元素添加條目。 新條目是存儲在mod.json中的字典詞典(下面的interface_config
):
{
"path": "{install}{site}{network}{clusters}{*}",
"install" : {
"site": {
"network": {
"clusters": {
"__iprange": {
"interface_config": {
"framesize": "1500",
"framesize_vm": "1500"
}
}
}
}
}
}
}
我還需要在原始json文件的不同部分中添加其他條目。
現在,我只是想遍歷test.json中的所有元素。 最終,我想為test.json中的每個元素構建一個路徑,並將其與mod.json中的路徑進行匹配以修改test.json。 但是,我無法將所有元素都打印在原始文件中。 我當前的代碼:
import json
import pprint
def traverse(d, path=None):
if path is None:
path = []
for item,val in d.iteritems():
if isinstance(item, dict):
for k,v in item.iteritems():
print k
traverse(v)
elif isinstance(item, list):
for j in item:
(traverse(j))
else:
print item
if isinstance(val, dict):
for k,v in val.iteritems():
print k
traverse(v)
elif isinstance(val, list):
for j in val:
(traverse(j))
with open("test.json", "r") as jf:
data = json.load(jf)
traverse(data)
上面的輸出是:
$ ./now.py
install
site
acls
dns
authorized_ports
Traceback (most recent call last):
File "./now.py", line 51, in <module>
traverse(data)
File "./now.py", line 23, in traverse
traverse(v)
File "./now.py", line 23, in traverse
traverse(v)
File "./now.py", line 26, in traverse
(traverse(j))
File "./now.py", line 9, in traverse
for item,val in d.iteritems():
AttributeError: 'unicode' object has no attribute 'iteritems'
我知道我的第一個iteritems
調用在錯誤的位置,但我只是無法確定遞歸...任何指針都iteritems
贊賞。 順便說一句,我在使用Python 2。
編輯
我要處理的實際json比上面列出的更為復雜。 這是一個編輯的版本:
{
"install": {
"site": {
"acls": {
"dns": {
"authorized_ports": ["53:tcp", "53:udp"]
}
},
"network": {
"clusters": {
"__ip_range_1__": {
"dhcpstart": "__ip__",
"dhcpend": "__ip__",
"adminip": "__ip__"
},
"__ip_range_2__": {
"dhcpstart": "__ip__",
"dhcpend": "__ip__",
"adminip": "__ip__"
}
}
}
}
}
"config": {
"ippool": [
{
"pool_name": "/ippool1",
"pool_description": "IP Pool1",
"ranges": [["__ip__", "__ip__"]]
},
{
"pool_name": "/ippool2",
"pool_description": "IP Pool2",
"ranges": [["__ip__", "__ip__"]]
}
],
"storage": [
{
"account": "/root",
"credentials": {
"account": "admin",
"service": "storage",
"user": "admin",
"password": "pass"
}
}
]
}
}
我修改了Paul Panzer的答案,使其包含以下列表:
def traverse(d, path=[]):
for k, v in d.iteritems():
yield path + [k], v
if isinstance(v, dict):
for k,v in traverse(v, path + [k]):
yield k,v
elif isinstance(v, list):
for k in v:
traverse(k, path + [])
但是,以上內容並未在ippool和存儲列表中顯示元素。 一旦遇到字典列表,出於某種原因就不會遍歷它。
這是traverse
例程的清理版本。 它只是遍歷嵌套的字典/列表; 為了清楚起見,我刪減了所有其他內容。 希望能幫助到你。
master = {
"install": {
"site": {
"acls": {
"dns": {
"authorized_ports": ["53:tcp", "53:udp"]
}
},
"network": {
"clusters": {
"__ip_range_1__": {
"dhcpstart": "__ip__",
"dhcpend": "__ip__",
"adminip": "__ip__"
},
"__ip_range_2__": {
"dhcpstart": "__ip__",
"dhcpend": "__ip__",
"adminip": "__ip__"
}
}
}
}
},
"config": {
"ippool": [
{
"pool_name": "/ippool1",
"pool_description": "IP Pool1",
"ranges": [["__ip__", "__ip__"]]
},
{
"pool_name": "/ippool2",
"pool_description": "IP Pool2",
"ranges": [["__ip__", "__ip__"]]
}
],
"storage": [
{
"account": "/root",
"credentials": {
"account": "admin",
"service": "storage",
"user": "admin",
"password": "pass"
}
}
]
}
}
def traverse(dict_or_list, path=[]):
if isinstance(dict_or_list, dict):
iterator = dict_or_list.iteritems()
else:
iterator = enumerate(dict_or_list)
for k, v in iterator:
yield path + [k], v
if isinstance(v, (dict, list)):
for k, v in traverse(v, path + [k]):
yield k, v
for path, node in traverse(master):
print path
輸出:
['config']
['config', 'ippool']
['config', 'ippool', 0]
['config', 'ippool', 0, 'ranges']
['config', 'ippool', 0, 'ranges', 0]
['config', 'ippool', 0, 'ranges', 0, 0]
['config', 'ippool', 0, 'ranges', 0, 1]
['config', 'ippool', 0, 'pool_name']
['config', 'ippool', 0, 'pool_description']
['config', 'ippool', 1]
['config', 'ippool', 1, 'ranges']
['config', 'ippool', 1, 'ranges', 0]
['config', 'ippool', 1, 'ranges', 0, 0]
['config', 'ippool', 1, 'ranges', 0, 1]
['config', 'ippool', 1, 'pool_name']
['config', 'ippool', 1, 'pool_description']
['config', 'storage']
['config', 'storage', 0]
['config', 'storage', 0, 'credentials']
['config', 'storage', 0, 'credentials', 'account']
['config', 'storage', 0, 'credentials', 'password']
['config', 'storage', 0, 'credentials', 'user']
['config', 'storage', 0, 'credentials', 'service']
['config', 'storage', 0, 'account']
['install']
['install', 'site']
['install', 'site', 'acls']
['install', 'site', 'acls', 'dns']
['install', 'site', 'acls', 'dns', 'authorized_ports']
['install', 'site', 'acls', 'dns', 'authorized_ports', 0]
['install', 'site', 'acls', 'dns', 'authorized_ports', 1]
['install', 'site', 'network']
['install', 'site', 'network', 'clusters']
['install', 'site', 'network', 'clusters', '__ip_range_2__']
['install', 'site', 'network', 'clusters', '__ip_range_2__', 'dhcpend']
['install', 'site', 'network', 'clusters', '__ip_range_2__', 'adminip']
['install', 'site', 'network', 'clusters', '__ip_range_2__', 'dhcpstart']
['install', 'site', 'network', 'clusters', '__ip_range_1__']
['install', 'site', 'network', 'clusters', '__ip_range_1__', 'dhcpend']
['install', 'site', 'network', 'clusters', '__ip_range_1__', 'adminip']
['install', 'site', 'network', 'clusters', '__ip_range_1__', 'dhcpstart']
似乎您希望使此操作變得不必要的復雜:
with open("test.json", "r") as jf:
data = json.load(jf)
with open("mod.json", "r") as mf:
mod = json.load(mf)
ip_ranges = data['install']['site']['network']['clusters']
for rng, val in mod['install']['site']['network']['clusters'].items():
data[rng]["interface_config"] = val["interface_config"]
來自AChampion的修改后的代碼,用於在具有動態鍵的字典的所有元素下添加條目:
with open(args.masterjson, "r") as masterjf:
data = json.load(masterjf)
with open(args.modjson, "r") as modjf:
mod = json.load(modjf)
new_value = mod['install']['site']['network']['clusters']['__iprange']['interface_config']
for rng, val in data['install']['site']['network']['clusters'].items():
data['install']['site']['network']['clusters'][rng]["interface_config"] = new_value
上面在集群中的每個IP范圍下添加了一個新的字典詞典。 輸出:
master BEFORE update:
{u'dhcpend': u'__ip__', u'adminip': u'__ip__', u'dhcpstart': u'__ip__'}
{u'dhcpend': u'__ip__', u'adminip': u'__ip__', u'dhcpstart': u'__ip__'}
master AFTER update:
{'interface_config': {u'framesize_vm': u'1500', u'framesize': u'1500'}, u'dhcpend': u'__ip__', u'adminip': u'__ip__', u'dhcpstart': u'__ip__'}
{'interface_config': {u'framesize_vm': u'1500', u'framesize': u'1500'}, u'dhcpend': u'__ip__', u'adminip': u'__ip__', u'dhcpstart': u'__ip__'}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.