【问题标题】:Create reversible YAML from JSON in python在 python 中从 JSON 创建可逆 YAML
【发布时间】:2019-05-27 09:11:32
【问题描述】:

在尝试从 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 应该出现的方式工作。需要有关如何完成它的建议。

【问题讨论】:

  • 我不确定您所说的“本机”PyYAML 究竟是什么意思,包括非本机、C、绑定,但是当您以您的方式使用 PyYAML 时它们不会被调用。

标签: python json yaml


【解决方案1】:

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'

【讨论】:

    【解决方案2】:

    只有 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()

    【讨论】:

      猜你喜欢
      • 2011-09-12
      • 2016-07-17
      • 1970-01-01
      • 2012-02-26
      • 1970-01-01
      • 2019-01-25
      • 2022-01-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多