繁体   English   中英

在 python 中从 JSON 创建可逆的 YAML

[英]Create reversible YAML from JSON in python

在尝试从 Python 中的 JSON 创建 YAML 时,使用 PyYAML 库,我能够将 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 出现的方式工作。 需要有关如何完成它的建议。

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'

只有 YAML 1.2 是 JSON 的超集,YAML 1.1 不是,虽然 YAML 1.2 于 2009 年发布,但遗憾的是 PyYAML 自那时以来一直没有更新。 您的示例是与 YAML 1.1 兼容的 JSON 子集,但一般来说,尝试使用 PyYAML 不是一个好主意。

Python 还有其他本机库,另一个是ruamel.yaml (免责声明:我是该包的作者),它实现了 YAML 1.2 并让您完全控制块与流样式转储单个集合。 当然,您仍然有一般的 YAML 限制,即您不能在流样式集合中拥有块样式集合)。

PyYAML 和非往返模式下的 ruamel.yaml 只允许您拥有所有块,或所有流,或所有带有流样式的叶节点的块。 但是默认的往返模式允许在集合上使用.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()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM