Создать обратимый YAML из JSON в Python - PullRequest
1 голос
/ 27 мая 2019

При попытке создать YAML из JSON в python, используя собственную библиотеку yaml, я могу преобразовать JSON в YAML. Тем не менее, в YAML, который я получаю в результате, все квадратные скобки JSON развернуты, тогда как я хочу сохранить несколько квадратных скобок (списков) из JSON в преобразованный YAML. Как я могу запросить этот библиотечный вызов, чтобы не раскрывать списки из JSON в YAML, а сохранять его как список?

Ниже приведен снимок моей проблемы:

import yaml
import json

original_json = {'a': {'next': ['b'], 'prev': []},
 'b': {'next': ['c'], 'prev': ['a']},
 'c': {'next': ['d', 'e'], 'prev': ['b']},
 'd': {'next': [], 'prev': ['c']},
 'e': {'next': ['f'], 'prev': ['c']},
 'f': {'next': [], 'prev': ['e']}}

obtained_yaml = yaml.dump(yaml.load(json.dumps(original_json)), default_flow_style=False)

# obtained_yaml looks like
#
# a:
#   next:
#   - b
#   prev: []
# b:
#   next:
#   - c
#   prev:
#   - a
# c:
#   next:
#   - d
#   - e
#   prev:
#   - b
# d:
#   next: []
#   prev:
#   - c
# e:
#   next:
#   - f
#   prev:
#   - c
# f:
#   next: []
#   prev:
#   - e

# expected yaml should look like
#
# a:
#   next:
#   - ["b"]
#   prev: []
# b:
#   next:
#   - ["c"]
#   prev:
#   - ["a"]
# c:
#   next:
#   - ["d"]
#   - ["e"]
#   prev:
#   - ["b"]
# d:
#   next: []
#   prev:
#   - ["c"]
# e:
#   next:
#   - ["f"]
#   prev:
#   - ["c"]
# f:
#   next: []
#   prev:
#   - ["e"]

Я пробовал несколько способов решить эту проблему, но все, что не сработало так, как ожидалось, должен появиться json. Нужны предложения о том, как это сделать.

Ответы [ 2 ]

1 голос
/ 27 мая 2019

Синтаксис Yaml определяет другую структуру списка, в которой членами списка являются строки, начинающиеся с одного и того же уровня отступа, начиная с - (тире и пробел).Если вы хотите сохранить скобки, вам нужно будет преобразовать свой список в str - но тогда вы потеряете возможность конвертировать YAML в JSON.

Вот пример, где вы можете видеть, что дажеесли вы можете получить ["a"] в [["a"]] - YAML преобразует его в список с двойным отступом:

In [4]: import yaml
   ...: import json
   ...: import collections
   ...: original_json = {'a': {'next': ['b'], 'prev': []},
   ...:  'b': {'next': ['c'], 'prev': ['a']},
   ...:  'c': {'next': ['d', 'e'], 'prev': ['b']},
   ...:  'd': {'next': [], 'prev': ['c']},
   ...:  'e': {'next': ['f'], 'prev': ['c']},
   ...:  'f': {'next': [], 'prev': ['e']}}
   ...:
   ...: mod_json = collections.defaultdict(dict)
   ...: for k, v in original_json.items():
   ...:     mod_json[k]["next"] = [v["next"]]
   ...:     mod_json[k]["prev"] = [v["prev"]]
   ...: obtained_yaml = yaml.dump(yaml.load(json.dumps(mod_json)), default_flow_style=False)
   ...:
   ...:

In [5]: obtained_yaml
Out[5]: 'a:\n  next:\n  - - b\n  prev:\n  - []\nb:\n  next:\n  - - c\n  prev:\n  - - a\nc:\n  next:\n  - - d\n    - e\n  prev:\n  - - b\nd:\n  next:\n  - []\n  prev:\n  - - c\ne:\n  next:\n  - - f\n  prev:\n  - - c\nf:\n  next:\n  - []\n  prev:\n  - - e\n'
0 голосов
/ 27 мая 2019

Только YAML 1.2 является расширенным набором JSON, YAML 1.1 - нет, и, хотя YAML 1.2 был выпущен в 2009 году, к сожалению, PyYAML с тех пор не обновлялся.Ваш пример - это подмножество JSON, совместимое с YAML 1.1, но в общем случае не стоит пытаться использовать для этого PyYAML.

Существуют и другие нативные библиотеки для Python, другая - ruamel.yaml(отказ от ответственности: я являюсь автором этого пакета), и он реализует YAML 1.2 и дает вам полный контроль над дампированием блоков и стилей потока отдельных коллекций.Конечно, у вас все еще есть общее ограничение YAML, что вы не можете иметь коллекцию стилей блоков в коллекции стилей потока).

PyYAML и ruamel.yaml в режиме non-round-trip-only, разрешают тольковесь блок, или весь поток, или весь блок с конечными узлами в стиле потока.Но по умолчанию режим туда-обратно позволяет более детализированное управление с использованием атрибута .fa для коллекций:

import sys
import json
import ruamel.yaml


original_json = {'a': {'next': ['b'], 'prev': []},
 'b': {'next': ['c'], 'prev': ['a']},
 'c': {'next': ['d', 'e'], 'prev': ['b']},
 'd': {'next': [], 'prev': ['c']},
 'e': {'next': ['f'], 'prev': ['c']},
 'f': {'next': [], 'prev': ['e']}}

json_string = json.dumps(original_json)

yaml = ruamel.yaml.YAML()
# yaml.indent(mapping=4, sequence=4, offset=2)
# yaml.preserve_quotes = True
data = yaml.load(json_string)

# the following sets flow-style for the root level mapping only
data.fa.set_block_style()
yaml.dump(data, sys.stdout)

, что дает:

a: {next: [b], prev: []}
b: {next: [c], prev: [a]}
c: {next: [d, e], prev: [b]}
d: {next: [], prev: [c]}
e: {next: [f], prev: [c]}
f: {next: [], prev: [e]}

, который вы, конечно, можете рекурсивно пройтисвою структуру данных и звоните .fa.set_block_style() в зависимости от любых критериев, которые вы хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...