LINUX.ORG.RU

Нубовопрос: как добавить пару ключ:значение в определенное место json'a на python

 , ,


0

1

Привет, ЛОР!

Возник нубовопрос.

Есть json примерно вот такой структуры:

{
	"main": [
		{
			"name": "CATEGORY0",
			"img": "img0.png",
			"subpages": [
				{
					"name": "name01",
					"img": "img01.png",
					"id": "27"
				},
				{
					"name": "name02",
					"img": "img02.png",
					"id": "35"
				}
				
			]
		},
		{
			"name": "CATEGORY1",
			"img": "img1.png",
			"subpages": [
				{
					"name": "name11",
					"img": "img11.png",
					"id": "850"
				}
			]
		},
		{
			"name": "CATEGORY2",
			"img": "img2.png",
			"subpages": [
				{
					"name": "Victim name",
					"img": "img21.png",
					"id": "843"
				},
				{
					"name": "name22",
					"img": "img22.png",
					"id": "999"
				},
				{
					"name": "name23",
					"img": "img23.png",
					"id": "997"
				}
			]
		},
		{
			"name": "CATEGORY3",
			"img": "img3.png",
			"subpages": [
				{
					"name": "name31",
					"img": "img31.png",
					"id": "979"
				}
			]
		}
	]
}

Задача: если в json'е присутсвует пара «name: Victim name», то добавить после этой секции еще одну.

Т.е.

#!/usr/bin/env python
# -*-coding: utf-8 -*-
import os
import json
json_data=open('categories.json')

data=json.load(json_data)
_str=json.dumps(data, indent=2, separators=(',',':'), ensure_ascii=False)
if 'Victim name' in _str:
  print('Найдено в categories.json')
  #здесь код по добавлению секции
else:
  print('Victim name не найден.')
  os.system('exit')

json_data.close()

Казалось бы, делай себе data['main']['category2'].append('some':stuff), но: проблема в том, что вложенность может быть различной, и я не могу предугадать количество индексов. ЛОР, как поступить? Метод перебора в цикле мне тоже кажется очень уж громоздским, ведь не известно, на каком уровне попадется «Victim name».

Еще в идеале хотелось бы вставлять нужную секцию сразу после секции с victim name. Такое вообще возможно?

★★

Последнее исправление: kir64 (всего исправлений: 1)

Ответ на: комментарий от theNamelessOne

Или написать кастомный декодер, который будет выполнять вот это:

хотелось бы вставлять нужную секцию сразу после секции с victim name.

во время парсинга. json.load вроде такое позволяет.

theNamelessOne ★★★★★
()

ЭЭЭ. Если ты не знаешь в каком дикте ключ, то тебе надо рекурсию от корня json и искать значение. Что то типа

p={1:1, 2:2, "key": {"123": 456}}

def f(obj, key, value):
...     if isinstance(obj, dict):
...             if key in obj and obj[key] == value:
...                     obj["new_key"] = "new_value"
...             else:
...                     for k, v in obj.iteritems():
...                             f(v, key, value)
...     elif isinstance(obj, list):
...             for i in obj:
...                     f(i, key, value)
        ...
... 
>>> f(p, "123", 456)
>>> p
{1: 1, 2: 2, 'key': {'new_key': 'new_value', '123': 456}}

energyclab
()

Я так понял, у тебя обязательно встречается структура типа:

{
  "name": "CATEGORY_NAME",
  "img": "IMG_FILE",
  "subpages": [
     ARRAY-OF-SUBPAGES
  ]
}
?

Ты ищешь среди массива ARRAY-OF-SUBPAGES подстраницу жертвы (объект {name, img, id}), и вставляешь в этот массив после жертвы ещё одну подстраницу? Или ты вставляешь пару ключ-значение в сам объект жертвы?

theNamelessOne ★★★★★
()
Ответ на: комментарий от theNamelessOne

Да, все верно, такая структура будет в любом случае. Если где-то в subpages содержится «victim name», то надо в тот же subpages после «victim name» добавить еще одну секцию, с тем же набором параметров, но другими значениями.

kir64 ★★
() автор топика
Ответ на: комментарий от theNamelessOne

Или ты вставляешь пару ключ-значение в сам объект жертвы?

Если это, всё легко:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import json

def add_some_shit_for_victim(dct):
    if 'name' in dct and dct['name'] == 'Victim name':
        dct['some'] = 'shit'
    return dct

def main():
    with open('categories.json', 'r') as json_data:
        data = json.load(json_data, object_hook=add_some_shit_for_victim)

        print data

if __name__ == '__main__':
    main()

Если тебе нужно вставлять данные в другое место, то задача немного усложняется, но сам принцип остаётся таким же.

theNamelessOne ★★★★★
()
Ответ на: комментарий от theNamelessOne

data = json.load(json_data, object_hook=add_some_shit_for_victim)

Круто, даже рекурсии не нужно... Не знал что так можно подправлять данные

energyclab
()
Ответ на: комментарий от kir64

Если где-то в subpages содержится «victim name», то надо в тот же subpages после «victim name» добавить еще одну секцию, с тем же набором параметров, но другими значениями.

Как-то так:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import json

def add_some_shit_for_victim(dct):
    if 'subpages' in dct:
        subpages = dct['subpages']
        victim = None
        for idx, subpage in enumerate(subpages):
            if subpage['name'] == 'Victim name':
                victim = idx
                break
        if victim is not None:
            # С тем же набором параметров, но с другими значениями
            new_page = {
                'name': 'foo',
                'img': 'foo.img',
                'id': '42'
            }
            subpages.insert(victim + 1, new_page)
    return dct

def main():
    with open('categories.json', 'r') as json_data:
        data = json.load(json_data, object_hook=add_some_shit_for_victim)
        print json.dumps(data, ensure_ascii=False, indent=2)

if __name__ == '__main__':
    main()

theNamelessOne ★★★★★
()
Последнее исправление: theNamelessOne (всего исправлений: 1)
Ответ на: комментарий от energyclab

Круто, даже рекурсии не нужно...

Рекурсия там уже есть: в самом json.load.

theNamelessOne ★★★★★
()
Ответ на: комментарий от theNamelessOne

Спаситель! Работает как часы, и именно так, как и хотелось!

Спасибо тебе огромное!

kir64 ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.