簡體   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