Python 如何使用嵌套的字典和列表迭代json的所有键?
我需要修改以下json文件test.json:Python 如何使用嵌套的字典和列表迭代json的所有键?,python,json,recursion,python-2.x,Python,Json,Recursion,Python 2.x,我需要修改以下json文件test.json: { "install": { "site": { "acls": { "dns": { "authorized_ports": ["53:tcp", "53:udp"] } }, "network": { "clusters": { "__ip_range_1__": { "dhcpstar
{
"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都不同。我需要向每个\uuuu ip\u range\u x\uuu
元素添加条目。新条目是存储在mod.json中的字典字典(interface\u 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
安装
地点
ACL
域名系统
授权港口
回溯(最近一次呼叫最后一次):
文件“/now.py”,第51行,在
导线测量(数据)
文件“/now.py”,导线测量中的第23行
导线测量(v)
文件“/now.py”,导线测量中的第23行
导线测量(v)
文件“/now.py”,导线测量中的第26行
(导线测量(j))
文件“/now.py”,导线测量中的第9行
对于项,d.iteritems()中的值:
AttributeError:“unicode”对象没有属性“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 + [])
但是,上述内容不会打印iPool和存储列表中的元素。一旦遇到字典列表,出于某种原因,它将不会被遍历。似乎您希望将其变得比必要的更复杂:
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"]
这是
遍历
例程的清理版本。它只遍历嵌套的字典/列表;为了清楚起见,我把其他的都删掉了。希望能有帮助
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']
来自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__'}
键(
item
)不能是list
s或dict
s,因此您的第一个条件是无用的。当val
是dict
时,您假设v
是dict
,这不是True
,因此您的错误。当val
是dict
时,您应该只递归traverse(val)
,而不是迭代val
,因此您的test.json在顶层只有一个键('install')。您的ip范围的“路径”是否始终相同?e、 g.总是在'install'>'site'>'network'>'clusters'?@MaxPower my test.json顶部有许多条目,有些是dict,有些是dict of dict,还有更复杂的,包括许多级别的dict和列表。但是,到uu ip_range_x的路径总是相同的。好吧,在这种情况下,AChampion的答案对你有用吗?@MaxPower它产生太多的值来解包错误。我在执行上述操作时遇到以下错误:对于rng,mod['install']['site']['network']['clusters']:ValueError:要解压缩的值太多-是因为val是一个dict吗?很抱歉,错过了.items()
它是一个dict
。此操作仍不起作用,出现以下错误:键错误:u'\u iprange'
。这是两个JSON,original和mod,不匹配的地方。此外,上面代码中的ip_范围
被指定了一个值,但从未使用过。目的是什么?如果我将赋值更改为data['install']['site']['network']['clusters'][rng][“interface\u config”]=new\u value
,它就会起作用。我将添加更正后的代码作为一个单独的答案,因为数据和mod也是颠倒的。谢谢,上面的工作很好。然而,我没有说明我的实际json有多复杂。它还包含嵌套字典的列表——因此我也尝试处理这些字典。我将用扩展的json更新我的问题。如果您还可以添加处理列表的代码,我很乐意接受您的回答。@Lidia添加了列表。让我知道这是否是你的想法。