Заменить значение в файле JSON для ключа, который может быть вложен в n уровней

У меня JSON, который выглядит так:

{
"ROLE_NAME": {
    "FOO": {
        "download_url": "http: //something.staging/12345/buzz.zip"
    },
    "BAR": {
        "download_url": "http: //something.staging/12345/fizz.zip"
    },
    "download_url": "http: //something.staging/12345/fizzbuzz.zip",
    "db_name": "somedb",
    "db_server": "dbserver.staging.dmz",
    "plugin": {
        "server_url": "http: //lab.staging.corp/server/"
    }
}
}

Я написал немного питона, который заменяет "download_url" k: v новым значением (т.е. новым download_url). К сожалению, он заменяет только один из трех download_urls в этом фрагменте json. Я понимаю, почему, но мне трудно получить решение, и поэтому я здесь прошу о помощи.

Весь объект json - это "данные" Поэтому я делаю что-то вроде этого:

data["ROLE_NAME"]["download_url"] = download_url

Где download_url - новое значение, которое я присвоил этой переменной Мне нужно сделать для любого ключа с именем [ "download_url" ], а затем обновить его, а не тот, который я указал на том слое, который я собираюсь.

Некоторые из моих кодов, которые помогут:

Я беру некоторые значения, полученные ранее в моем коде, и строю url, который возвращает ответ. Я извлекаю значение из ответа, которое будет использоваться для создания значения download_url

buildinfo_url = "http://something.staging/guestAuth/app/rest/builds/?locator=buildType:%s,tags:%s,branch:branched:any" % (
    bt_number,
    list_json_load[role_name][0]['tag']
)

Отправить HTTP-запрос

client = httplib2.Http()
response, xml = client.request(buildinfo_url)

Извлеките некоторое значение из ответа xml и установите переменную download_url

doc = ElementTree.fromstring(xml)
for id in doc.findall('build'):
    build_id = "%s" % (id.attrib['id'])
try:
    download_url = "http://something.staging/guestAuth/repository/download/%s/%s:id/%s" % (
        bt_number,
        build_id,
        build_artifact_zip
    )
    data[role_name]["download_url"] = download_url
except NameError:
    print "something"

Я думаю, что мне нужно рекурсивно искать и обновлять

Ответ 1

Использование рекурсии

import json   
json_txt = """
{
"ROLE_NAME": {
    "FOO": {
        "download_url": "http: //something.staging/12345/buzz.zip"
    },
    "BAR": {
        "download_url": "http: //something.staging/12345/fizz.zip"
    },
    "download_url": "http: //something.staging/12345/fizzbuzz.zip",
    "db_name": "somedb",
    "db_server": "dbserver.staging.dmz",
    "plugin": {
        "server_url": "http: //lab.staging.corp/server/"
    }
}
}
"""
data = json.loads(json_txt)

def fixup(adict, k, v):
    for key in adict.keys():
        if key == k:
            adict[key] = v
        elif type(adict[key]) is dict:
            fixup(adict[key], k, v)

import pprint
pprint.pprint( data )

fixup(data, 'download_url', 'XXX')

pprint.pprint( data )

Вывод:

{u'ROLE_NAME': {u'BAR': {u'download_url': u'http: //something.staging/12345/fizz.zip'},
                u'FOO': {u'download_url': u'http: //something.staging/12345/buzz.zip'},
                u'db_name': u'somedb',
                u'db_server': u'dbserver.staging.dmz',
                u'download_url': u'http: //something.staging/12345/fizzbuzz.zip',
                u'plugin': {u'server_url': u'http: //lab.staging.corp/server/'}}}
{u'ROLE_NAME': {u'BAR': {u'download_url': 'XXX'},
                u'FOO': {u'download_url': 'XXX'},
                u'db_name': u'somedb',
                u'db_server': u'dbserver.staging.dmz',
                u'download_url': 'XXX',
                u'plugin': {u'server_url': u'http: //lab.staging.corp/server/'}}}