Перебор строк в кодировке JSON, найденных внутри документа

У меня возникают проблемы с повторением json, содержащего вложенные строки json (с экранированными кавычками).

(Заранее извиняюсь, я новичок и, вероятно, упускаю какую-то важную информацию...)

Собственно у меня несколько вопросов:

1) Как я могу выполнить итерацию (как я пытался сделать ниже с вложенными циклами for) через элементы под «содержимым раздела» раздела «узлы» (! не раздела «имена элементов»!)? Моя проблема заключается в том, что содержимое раздела представляет собой строку с экранированными кавычками, которая сама по себе представляет собой отдельную строку json.

2) Является ли приведенный пример JSON действительным json? Я попробовал несколько валидаторов, и все они, кажется, терпят неудачу, когда в игру вступают экранированные кавычки.

3) Есть ли более разумный метод доступа к определенным элементам вместо простого перебора всего дерева? Я думаю о чем-то, что указывает пары ключ/значение, например:

my_json_obj['sections']['section-id' = 'nodes']['section-content']['occ_id' = '051MZjd97jUdYfSEOG}k10']

Код:

import json
import requests
import pprint

client = requests.session()
header = {'X-CSRF-Token': 'Fetch', 'Accept': 'application/json', 'Content-Type': 'application/json'}
response = client.get('http://xxxxxx.xxx/ProcessManagement/BranchContentSet(BranchId=\'051MZjd97jUdYfX7{dREAm\',SiteId=\'\',SystemRole=\'D\')/$value',auth=('TestUser', 'TestPass'),headers=header)

my_json_obj = response.json()

sections = my_json_obj['sections']
for mysection in sections:
    print(mysection['section-id'])
    if mysection['section-id'] == 'NODES':
        nodes = mysection['section-content'] #nodes seems to be string 
        for mynode in nodes:
            print(mynode) #prints string character by character

Пример JSON:

{
  "smud-data-version": "0.1",
  "sections": [
    {
      "section-id": "ELEMENT-NAMES",
      "section-content-version": "",
      "section-content": "{\"D\":[
    {\"occ_id\":\"051MZjd97kcBgtZiEI0IvW\",\"lang\":\"E\",\"name\":\"0TD1 manuell\"},
    {\"occ_id\":\"051MZjd97kcBgtZiEH}IvW\",\"lang\":\"E\",\"name\":\"Documentation\"}
      ]}"
    },
    {
      "section-id": "NODES",
      "section-content-version": "1.0",
      "section-content": "[
        {\"occ_id\":\"051MZjd97jUdYfSEOG}k10\",\"obj_type\":\"ROOT\",\"reference\":\"\",\"deleted\":\"\",\"attributes\":[]},
        {\"occ_id\":\"051MZjd97jUdYfSEOH0k10\",\"obj_type\":\"ROOTGRP\",\"reference\":\"\",\"deleted\":\"\",\"attributes\":[]},
        {\"occ_id\":\"051MZjd97jcAnKoe03JRRm\",\"obj_type\":\"SCN\",\"reference\":\"\",\"deleted\":\"\",\"attributes\":[
            {\"attr_type\":\"NODE_CHANGED_AT\",\"lang\":\"\",\"values\":[\"20190213095843\"]},
            {\"attr_type\":\"NODE_CHANGED_BY\",\"lang\":\"\",\"values\":[\"TestUser\"]},
            {\"attr_type\":\"TCASSIGNMENTTYPE\",\"lang\":\"\",\"values\":[\"A\"]},
            {\"attr_type\":\"DESCRIPTION\",\"lang\":\"E\",\"values\":[\"Scenario\"]}
        ]}
    ]"
    }
  ]
}

Фактический результат:

ELEMENT-NAMES
NODES
[
{
"
o
c
c
_
i
d
"

Действительно, похоже, что у section-content есть второй/отдельный уровень кодирования JSON — это очень... эээ... действие необычный со стороны людей, которые его создали. Однако декодируйте его с помощью json.loads(), и вот вы — нативная структура данных Python.

Charles Duffy 13.02.2019 17:39

Действительно, это недопустимый JSON. Буквальные символы новой строки внутри строки в кавычках вместо этого должны быть \ns. Однако проще всего просто удалить их.

Charles Duffy 13.02.2019 17:42

@Чарльз Даффи Microsoft делает это для некоторых своих API, например, в манифестах обработчиков файлов OneDrive.. Эта документация говорит, что это «из-за ограничений в расширениях надстроек Azure Active Directory эти действия хранятся сериализованными в строку».

Giacomo Alzetta 13.02.2019 17:51

@GiacomoAlzetta, ... поэтому они решили превратить свой технический долг в проблему своих конечных пользователей? Типичный.

Charles Duffy 13.02.2019 17:55

@Charles Duffy: извините, я добавил буквальные новые строки, чтобы сделать json более читаемым / добавить какой-то отступ, который выделяет структуру (даже если она находится внутри закодированной строки).

JHM 13.02.2019 19:21

@JHM, ааа. Пожалуйста, постарайтесь убедиться, что когда вы включаете данные, они остаются пригодными для использования кем-то, кто проверяет правильность своих ответов, и, по крайней мере, громко отмечайте, когда вы вносите изменения, противоречащие этой цели.

Charles Duffy 13.02.2019 19:23
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
6
75
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Надеюсь, вы сможете убедить людей, которые генерируют эти данные, починить свой сервер. Тем не менее, решение проблем может выглядеть так:

# instead of using requests.json(), remove literal newlines and then decode ourselves
# ...because the original data has newline literals in positions where they aren't allowed.
my_json_obj = json.loads(response.text.replace('\n', ''))

for section in my_json_obj['sections']:
    if section['section-id'] != 'NODES': continue
    # doing another json.loads() here so you treat content as an array, not a string
    for node in json.loads(section['section-content']):
        __import__('pprint').pprint(node)

... правильно испускает в качестве вывода:

{u'attributes': [],
 u'deleted': u'',
 u'obj_type': u'ROOT',
 u'occ_id': u'051MZjd97jUdYfSEOG}k10',
 u'reference': u''}
{u'attributes': [],
 u'deleted': u'',
 u'obj_type': u'ROOTGRP',
 u'occ_id': u'051MZjd97jUdYfSEOH0k10',
 u'reference': u''}
{u'attributes': [{u'attr_type': u'NODE_CHANGED_AT',
                  u'lang': u'',
                  u'values': [u'20190213095843']},
                 {u'attr_type': u'NODE_CHANGED_BY',
                  u'lang': u'',
                  u'values': [u'TestUser']},
                 {u'attr_type': u'TCASSIGNMENTTYPE',
                  u'lang': u'',
                  u'values': [u'A']},
                 {u'attr_type': u'DESCRIPTION',
                  u'lang': u'E',
                  u'values': [u'Scenario']}],
 u'deleted': u'',
 u'obj_type': u'SCN',
 u'occ_id': u'051MZjd97jcAnKoe03JRRm',
 u'reference': u''}```

Другие вопросы по теме