[英]Python YAML to JSON to YAML
我是 python 的新手,所以我正在構建一個簡單的程序來將 YAML 解析為 JSON,並將 JSON 解析為 YAML。
yaml2json
在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 流樣式寫入所有葉節點,而您的輸入一直是塊樣式。
您還丟失了鍵的順序,這首先是因為 JSON 解析器使用 dict,其次是因為dump
對輸出進行了排序。
如果您查看中間 JSON,您已經看到此時鍵順序已經消失。 為了保留這一點,請使用新的 API 來加載您的 YAML,並使用一個特殊的 JSON 編碼器作為轉儲的替代品,該編碼器可以處理Mapping
的子類,其中加載了 YAML,類似於標准 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 具有適當的鍵順序,我們也需要在加載時保留該順序。 您可以通過提供object_pairs_hook
來指定將 JSON對象加載到 YAML 解析器在內部使用的Mapping
的子類中,而無需子類化任何內容。
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
作為ruamel.yaml.YAML()
實例的名稱,而不是from ruamel import yaml
。 然而,這掩蓋了yaml.YAMLError
的使用,因為錯誤類不是YAML()
的屬性
如果您正在開發此類東西,我建議至少從實際功能中刪除用戶輸入。 編寫parseyaml
和parsejson
來調用yaml_2_json
應該很簡單。 json_2_yaml
。
盡管 ruamel.yaml 可以加載它們,但原始 YAML 文件中的任何注釋都將丟失。 JSON 最初確實允許評論,但它不在規范中,我知道沒有解析器可以輸出評論。
由於您的真實文件具有文字塊標量,因此您必須使用一些魔法來恢復它們。
包括以下函數,它們遍歷樹、遞歸到 dict 值和列表元素並將任何帶有嵌入換行符的行轉換為一種類型,該類型將輸出到 YAML 作為原位塊樣式標量(因此沒有返回值):
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
文件中應該只有一行不同。
function yaml_validate {
python -c 'import sys, yaml, json; yaml.safe_load(sys.stdin.read())'
}
function yaml2json {
python -c 'import sys, yaml, json; print(json.dumps(yaml.safe_load(sys.stdin.read())))'
}
function yaml2json_pretty {
python -c 'import sys, yaml, json; print(json.dumps(yaml.safe_load(sys.stdin.read()), indent=2, sort_keys=False))'
}
function json_validate {
python -c 'import sys, yaml, json; json.loads(sys.stdin.read())'
}
function json2yaml {
python -c 'import sys, yaml, json; print(yaml.dump(json.loads(sys.stdin.read())))'
}
更多有用的 Bash 技巧,請訪問http://github.com/frgomes/bash-scripts
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.