簡體   English   中英

Python YAML 到 JSON 到 YAML

[英]Python YAML to JSON to YAML

我是 python 的新手,所以我正在構建一個簡單的程序來將 YAML 解析為 JSON,並將 JSON 解析為 YAML。

yaml2jsonyaml2json中將 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()的屬性

  • 如果您正在開發此類東西,我建議至少從實際功能中刪除用戶輸入。 編寫parseyamlparsejson來調用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM