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

Начал применять Python в автотестах. Есть Json типа

{
  "someKey": {
   "anotherKey": {
     "oneMoreKey": [
       {
  "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ",
  "startTime": "00.000",
  "stopTime": "00.001",
  "id": "some"
},
       {
         "key1": {
           "key23": [
                    {
  "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ",
  "startTime": "00.000",
  "stopTime": "00.001",
  "id": "some"
}
           ]
         }
       }
     ]
   }
  }
}
  1. Рекурсивно пропарить JSON, найти ключ "text" (сделано, функция - ниже)
    def json_find(d, key):
        if isinstance(d, dict):
            if key in d.keys():
                return d.get(key)
            return "".join([json_find(d[k], key) for k in d.keys()])
        elif isinstance(d, list):
            return "".join([json_find(x, key) for x in d])
        else:
            return ""

    print(json_find(data, search_key))
  1. Найти что-то в значении ключа "text"
  2. Если поиск успешен - получить значение ключа "id"

Помогите пожалуйста с 3-м пунктом. "Переклинило"


Ответы (1 шт):

Автор решения: insolor

В целом по поводу рекурсивного поиска:

Не нужно джоинить результаты вложенных веток в одну строку. Возвращайте или найденный результат (один конкретный результат), или None, если ничего не найдено. По итерируемым последовательностям (спискам или значениям словаря) проходите обычным циклом, на каждом элементе вызывайте функцию рекурсивно. Если вернулось не None (что-то найдено) - возвращаете результат наружу.

data = {
  "someKey": {
   "anotherKey": {
     "oneMoreKey": [
       {
  "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ",
  "startTime": "00.000",
  "stopTime": "00.001",
  "id": "some"
},
       {
         "key1": {
           "key23": [
                    {
  "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ",
  "startTime": "00.000",
  "stopTime": "00.001",
  "id": "some"
}
           ]
         }
       }
     ]
   }
  }
}


def json_find(d, needle):
    if isinstance(d, dict):
        if needle in d:
            return d[needle]
        
        for value in d.values():
            result = json_find(value, needle)
            if result is not None:
                return result
    elif isinstance(d, list):
        for value in d:
            result = json_find(value, needle)
            if result is not None:
                return result

    return None


print(json_find(data, "text"))

Результат:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Значение по ключу "id" можно вернуть например вторым элементом, общий результат поиска будет кортежом:

...
return d[needle], d["id"]  # вместо return d[needle]
...

Получится

('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ', 'some')

Если вдруг нужно будет найти все словари с ключом "text", и из них вернуть значения, то заменяете обычную рекурсивную функцию на рекурсивный генератор, выводите результаты, например, циклом:

data = {
    "someKey": {
        "anotherKey": {
            "oneMoreKey": [
                {
                    "text": "Text1",
                    "startTime": "00.000",
                    "stopTime": "00.001",
                    "id": "id1",
                },
                {
                    "key1": {
                        "key23": [
                            {
                                "text": "Text2",
                                "startTime": "00.000",
                                "stopTime": "00.001",
                                "id": "id2",
                            }
                        ]
                    }
                },
            ]
        }
    }
}


def json_find(d, needle):
    if isinstance(d, dict):
        if needle in d:
            yield d[needle], d["id"]

        for value in d.values():
            yield from json_find(value, needle)

    elif isinstance(d, list):
        for value in d:
            yield from json_find(value, needle)


for text, id_ in json_find(data, "text"):
    print(f"id: {id_}, text: {text}")

Вывод:

id: id1, text: Text1
id: id2, text: Text2
→ Ссылка