将带有标签的 YAML 转储为 JSON
dumping YAML with tags as JSON
我知道我可以使用 ruamel.yaml 加载带有标签的文件。但是当我想在没有它们的情况下转储时,我得到了一个错误。简化示例:-
from ruamel.yaml import YAML
from json import dumps
import sys
yaml = YAML()
data = yaml.load(
"""
!mytag
a: 1
b: 2
c: 2022-05-01
"""
)
try:
yaml2 = YAML(typ='safe', pure=True)
yaml.default_flow_style = True
yaml2.dump(data, sys.stdout)
except Exception as e:
print('exception dumping using yaml', e)
try:
print(dumps(data))
except Exception as e:
print('exception dumping using json', e)
exception dumping using cannot represent an object: ordereddict([('a', 1), ('b', 2), ('c', datetime.date(2022, 5, 1))])
exception dumping using json Object of type date is not JSON serializable
我无法更改 load() 而不会在标签上出现错误。如何获得剥离标签的输出(YAML 或 JSON)?
你得到这个错误是因为既不是安全的转储程序(无论是否纯正),也不是 JSON,不了解 ruamel.yaml
内部
保留注释、标记、block/flow-style 等的类型
转储为 YAML,您可以使用备用转储方法注册这些类型。由于 JSON 这更复杂
作为 AFAIK,你只能转换 leaf-nodes (即 YAML 标量,你会是
能够使用它来转储作为键值 c
).
加载的 datetime.datetime
实例
我将 YAML 用作可读、可编辑和以编程方式更新的配置文件
如果文件不早于相应的 YAML(如果
它较旧 JSON 是从 YAML 创建的)。为了 dump(s)
要做的事情是
递归生成 Python 原语 JSON 理解。
下面是这样做的,但是除了日期时间之外还有其他构造
JSON 不允许的实例。例如。使用序列或字典时
作为键(在 YAML 中允许,但在 JSON 中不允许)。对于那些是
sequences 我连接元素的字符串表示
:
from ruamel.yaml import YAML
import sys
import datetime
import json
from collections.abc import Mapping
yaml = YAML()
data = yaml.load("""\
!mytag
a: 1
b: 2
c: 2022-05-01
[d, e]: !myseq [42, 196]
{f: g, 18: y}: !myscalar x
""")
def json_dump(data, out, indent=None):
def scalar(obj):
if obj is None:
return None
if isinstance(obj, (datetime.date, datetime.datetime)):
return str(obj)
if isinstance(obj, ruamel.yaml.scalarbool.ScalarBoolean):
return obj == 1
if isinstance(obj, bool):
return bool(obj)
if isinstance(obj, int):
return int(obj)
if isinstance(obj, float):
return float(obj)
if isinstance(obj, tuple):
return '_'.join([str(x) for x in obj])
if isinstance(obj, Mapping):
return '_'.join([f'{k}-{v}' for k, v in obj.items()])
if not isinstance(obj, str): print('type', type(obj))
return obj
def prep(obj):
if isinstance(obj, dict):
return {scalar(k): prep(v) for k, v in obj.items()}
if isinstance(obj, list):
return [prep(elem) for elem in obj]
if isinstance(obj, ruamel.yaml.comments.TaggedScalar):
return prep(obj.value)
return scalar(obj)
res = prep(data)
json.dump(res, out, indent=indent)
json_dump(data, sys.stdout, indent=2)
给出:
{
"a": 1,
"b": 2,
"c": "2022-05-01",
"d_e": [
42,
196
],
"f-g_18-y": "x"
}
我知道我可以使用 ruamel.yaml 加载带有标签的文件。但是当我想在没有它们的情况下转储时,我得到了一个错误。简化示例:-
from ruamel.yaml import YAML
from json import dumps
import sys
yaml = YAML()
data = yaml.load(
"""
!mytag
a: 1
b: 2
c: 2022-05-01
"""
)
try:
yaml2 = YAML(typ='safe', pure=True)
yaml.default_flow_style = True
yaml2.dump(data, sys.stdout)
except Exception as e:
print('exception dumping using yaml', e)
try:
print(dumps(data))
except Exception as e:
print('exception dumping using json', e)
exception dumping using cannot represent an object: ordereddict([('a', 1), ('b', 2), ('c', datetime.date(2022, 5, 1))])
exception dumping using json Object of type date is not JSON serializable
我无法更改 load() 而不会在标签上出现错误。如何获得剥离标签的输出(YAML 或 JSON)?
你得到这个错误是因为既不是安全的转储程序(无论是否纯正),也不是 JSON,不了解 ruamel.yaml
内部
保留注释、标记、block/flow-style 等的类型
转储为 YAML,您可以使用备用转储方法注册这些类型。由于 JSON 这更复杂
作为 AFAIK,你只能转换 leaf-nodes (即 YAML 标量,你会是
能够使用它来转储作为键值 c
).
datetime.datetime
实例
我将 YAML 用作可读、可编辑和以编程方式更新的配置文件
如果文件不早于相应的 YAML(如果
它较旧 JSON 是从 YAML 创建的)。为了 dump(s)
要做的事情是
递归生成 Python 原语 JSON 理解。
下面是这样做的,但是除了日期时间之外还有其他构造 JSON 不允许的实例。例如。使用序列或字典时 作为键(在 YAML 中允许,但在 JSON 中不允许)。对于那些是 sequences 我连接元素的字符串表示 :
from ruamel.yaml import YAML
import sys
import datetime
import json
from collections.abc import Mapping
yaml = YAML()
data = yaml.load("""\
!mytag
a: 1
b: 2
c: 2022-05-01
[d, e]: !myseq [42, 196]
{f: g, 18: y}: !myscalar x
""")
def json_dump(data, out, indent=None):
def scalar(obj):
if obj is None:
return None
if isinstance(obj, (datetime.date, datetime.datetime)):
return str(obj)
if isinstance(obj, ruamel.yaml.scalarbool.ScalarBoolean):
return obj == 1
if isinstance(obj, bool):
return bool(obj)
if isinstance(obj, int):
return int(obj)
if isinstance(obj, float):
return float(obj)
if isinstance(obj, tuple):
return '_'.join([str(x) for x in obj])
if isinstance(obj, Mapping):
return '_'.join([f'{k}-{v}' for k, v in obj.items()])
if not isinstance(obj, str): print('type', type(obj))
return obj
def prep(obj):
if isinstance(obj, dict):
return {scalar(k): prep(v) for k, v in obj.items()}
if isinstance(obj, list):
return [prep(elem) for elem in obj]
if isinstance(obj, ruamel.yaml.comments.TaggedScalar):
return prep(obj.value)
return scalar(obj)
res = prep(data)
json.dump(res, out, indent=indent)
json_dump(data, sys.stdout, indent=2)
给出:
{
"a": 1,
"b": 2,
"c": "2022-05-01",
"d_e": [
42,
196
],
"f-g_18-y": "x"
}