gpt4 book ai didi

Python YAML 到 JSON 到 YAML

转载 作者:行者123 更新时间:2023-11-28 17:04:33 26 4
gpt4 key购买 nike

我是 python 的新手,所以我正在构建一个简单的程序来将 YAML 解析为 JSON 以及将 JSON 解析为 YAML。

yaml2json 在一行中将 YAML 转换为 JSON,但 JSON 验证器认为它是正确的。

到目前为止,这是我的代码:

def parseyaml(inFileType, outFileType):
infile = input('Please enter a {} filename to parse: '.format(inFileType))
outfile = input('Please enter a {} filename to output: '.format(outFileType))

with open(infile, 'r') as stream:
try:
datamap = yaml.safe_load(stream)
with open(outfile, 'w') as output:
json.dump(datamap, output)
except yaml.YAMLError as exc:
print(exc)

print('Your file has been parsed.\n\n')


def parsejson(inFileType, outFileType):
infile = input('Please enter a {} filename to parse: '.format(inFileType))
outfile = input('Please enter a {} filename to output: '.format(outFileType))

with open(infile, 'r') as stream:
try:
datamap = json.load(stream)
with open(outfile, 'w') as output:
yaml.dump(datamap, output)
except yaml.YAMLError as exc:
print(exc)

print('Your file has been parsed.\n\n')

原始 YAML 与新 YAML 的示例

原文:

inputs:
webTierCpu:
type: integer
minimum: 2
default: 2
maximum: 5
title: Web Server CPU Count
description: The number of CPUs for the Web nodes

新:

inputs:
dbTierCpu: {default: 2, description: The number of CPUs for the DB node, maximum: 5,
minimum: 2, title: DB Server CPU Count, type: integer}

它看起来不像是对所有 JSON 进行解码,所以我不确定下一步应该去哪里......

最佳答案

您的文件正在丢失其格式,因为原始的 dump 例程默认情况下以 YAML 流式写入所有叶节点,而您的输入是 block 式一路走来。

您还丢失了键的顺序,首先是因为 JSON 解析器使用 dict,其次是因为 dump 对输出进行排序。

如果您查看中间 JSON,您已经看到键顺序是在那一点上消失了。要保留它,请使用新的 API 加载您的 YAML并有一个特殊的 JSON 编码器作为转储的替代品,可以处理加载 YAML 的 Mapping 的子类,类似于 this例子来自标准 Python 文档。

假设您的 YAML 存储在 input.yaml 中:

import sys
import json
from collections.abc import Mapping, Sequence
from collections import OrderedDict
import ruamel.yaml

# if you instantiate a YAML instance as yaml, you have to explicitly import the error
from ruamel.yaml.error import YAMLError


yaml = ruamel.yaml.YAML() # this uses the new API
# if you have standard indentation, no need to use the following
yaml.indent(sequence=4, offset=2)

input_file = 'input.yaml'
intermediate_file = 'intermediate.json'
output_file = 'output.yaml'


class OrderlyJSONEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, Mapping):
return OrderedDict(o)
elif isinstance(o, Sequence):
return list(o)
return json.JSONEncoder.default(self, o)


def yaml_2_json(in_file, out_file):
with open(in_file, 'r') as stream:
try:
datamap = yaml.load(stream)
with open(out_file, 'w') as output:
output.write(OrderlyJSONEncoder(indent=2).encode(datamap))
except YAMLError as exc:
print(exc)
return False
return True


yaml_2_json(input_file, intermediate_file)
with open(intermediate_file) as fp:
sys.stdout.write(fp.read())

给出:

{
"inputs": {
"webTierCpu": {
"type": "integer",
"minimum": 2,
"default": 2,
"maximum": 5,
"title": "Web Server CPU Count",
"description": "The number of CPUs for the Web nodes"
}
}
}

您看到您的 JSON 具有适当的键顺序,我们也需要在加载时保存。你可以在没有子类化的情况下做到这一点任何东西,通过指定将 JSON 对象加载到的子类中映射,YAML 解析器通过提供object_pairs_hook 在内部使用。

from ruamel.yaml.comments import CommentedMap


def json_2_yaml(in_file, out_file):
with open(in_file, 'r') as stream:
try:
datamap = json.load(stream, object_pairs_hook=CommentedMap)
# if you need to "restore" literal style scalars, etc.
# walk_tree(datamap)
with open(out_file, 'w') as output:
yaml.dump(datamap, output)
except yaml.YAMLError as exc:
print(exc)
return False
return True


json_2_yaml(intermediate_file, output_file)
with open(output_file) as fp:
sys.stdout.write(fp.read())

哪些输出:

inputs:
webTierCpu:
type: integer
minimum: 2
default: 2
maximum: 5
title: Web Server CPU Count
description: The number of CPUs for the Web nodes

而且我希望这与您的原始输入足够相似以便可以接受。

注意事项:

  • 在使用新 API 时,我倾向于使用 yaml 作为 API 的名称ruamel.yaml.YAML() 的实例,而不是 from ruamel import
    yaml
    。然而,这掩盖了 yaml.YAMLError 的使用,因为错误类不是 YAML()

  • 的属性
  • 如果您正在开发此类内容,我建议您删除至少来自实际功能的用户输入。它应该是编写 parseyamlparsejson 来调用 yaml_2_json 很简单。json_2_yaml

  • 原始 YAML 文件中的任何注释都将丢失,尽管ruamel.yaml 可以加载它们。 JSON 最初确实允许注释,但现在不在规范中,而且我知道没有任何解析器可以输出注释。


由于您的真实文件具有文字 block 标量,您必须使用一些魔法来取回它们。

包括以下遍历树的函数,递归到 dict 值和列表元素中,并将带有嵌入式换行符的任何行转换为一种类型,该类型将输出到 YAML 作为就地文字 block 样式标量(因此没有返回值):

from ruamel.yaml.scalarstring import PreservedScalarString, SingleQuotedScalarString
from ruamel.yaml.compat import string_types, MutableMapping, MutableSequence

def preserve_literal(s):
return PreservedScalarString(s.replace('\r\n', '\n').replace('\r', '\n'))

def walk_tree(base):
if isinstance(base, MutableMapping):
for k in base:
v = base[k] # type: Text
if isinstance(v, string_types):
if '\n' in v:
base[k] = preserve_literal(v)
elif '${' in v or ':' in v:
base[k] = SingleQuotedScalarString(v)
else:
walk_tree(v)
elif isinstance(base, MutableSequence):
for idx, elem in enumerate(base):
if isinstance(elem, string_types):
if '\n' in elem:
base[idx] = preserve_literal(elem)
elif '${' in elem or ':' in elem:
base[idx] = SingleQuotedScalarString(elem)
else:
walk_tree(elem)

然后做

    walk_tree(datamap)

从 JSON 加载数据后。

对于以上所有内容,您的 Wordpress.yaml 文件中应该只有一行不同。

关于Python YAML 到 JSON 到 YAML,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51914505/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com