【问题标题】:Add custom fields to JSON file based on user input from YAML file - Python3根据来自 YAML 文件的用户输入向 JSON 文件添加自定义字段 - Python3
【发布时间】:2019-07-11 21:17:05
【问题描述】:

我是 Python 新手。我有一个 YAML 文件,我正在使用 Python 文件访问它。在 YAML 文件中,有 fields 选项。在 YAML 文件中,用户可以使用值设置变量。 Python 文件读取带有值的变量,然后将其添加到 JSON 文件中。请注意,变量和值可以根据用户进行更改。
我怎样才能做到这一点?

这里是示例代码:

import yaml
from datetime import datetime
import os
import json

#name for json file
name = "stack.json"

#load data from yml file
data = yaml.safe_load(open('stack.yml'))
data2 = data.get('heartbeat.monitors')

#Current time stamp
timestamp = datetime.now().strftime("%B %d %Y, %H:%M:%S")

#ip
ip ='192.168.1.1'

#getting data from the field and assign it to variable
for item in data2:
    if item["type"] == "icmp":
        fields_under_root = (item["fields_under_root"])

        # if fields_under_root is true,code goes here
        if fields_under_root == True:
            fields = (item["fields"])
            print(fields)
            locals().update(fields)
        #code to be entered

        #if fields_under_root is false, code goes here
        elif fields_under_root == False:
            fields = (item["fields"])
            print(fields)
        #code to be entered
#For writing in JSON File
#Creates a JSON file if not exists
if not os.path.exists(name):
    with open(name, 'w') as f:
        f.write('{}')

#list for storing the values
result = [(timestamp, {'monitor.ip': ip,"fields": fields })]

#For writing in JSON File
with open(name, 'rb+') as f:
    f.seek(-1, os.SEEK_END)
    f.truncate()
    for entry in result:
        _entry = '"{}":{},\n'.format(entry[0], json.dumps(entry[1]))
        _entry = _entry.encode()
        f.write(_entry)
    f.write('}'.encode('ascii'))

在 YAML 文件中:

heartbeat.monitors:
- type: icmp
  fields:
    a: steven
    b: kumar

  fields_under_root: True

我在 JSON 文件中的输出:

{"February 18 2019, 17:04:30":{"monitor.ip": "192.168.1.1", "fields": {"b": "kumar", "a": "steven"}},
}

如果fields_under_rootTrue,则需要输出:

{"February 18 2019, 17:04:30":{"monitor.ip": "192.168.1.1", "b": "kumar", "a": "steven"},
}

如果fields_under_rootFalse,则需要输出:

{"February 18 2019, 17:04:30":{"monitor.ip": "192.168.1.1", "fields.b": "kumar", "fields.a": "steven"},
}

【问题讨论】:

  • 为什么代码中的条件检查做同样的事情?还有你为什么要更新locals
  • 我没有在条件字段上添加代码。告诉我一些关于输出的建议。
  • 下一次,只需编辑您的问题而不是 deleting 它,然后将内容复制并粘贴到一个新问题中。

标签: python json python-3.x yaml


【解决方案1】:

给定一个输入文件:

...

heartbeat.monitors:
- type: icmp
  fields:
    a: steven
    b: kumar
  # If this option is set to true, the custom fields are stored as top-level
  # fields in the output document instead of being grouped under a fields
  # sub-dictionary. Default is false.
  fields_under_root: True

你的程序应该有一个可以完成所有工作的函数,那么它很容易测试 两个版本的输入,通过更新输入文件。:

import ruamel.yaml
from datetime import datetime
import os
import json

# name for json file
json_name = 'stack.json'
yaml_name = 'stack.yaml'


# Current time stamp
timestamp = datetime.now().strftime('%B %d %Y, %H:%M:%S')


def gen_output(data, json_filename):
    ip = '192.168.1.1'
    val = {'monitor.ip': ip}
    result = dict(timestamp=val)

    # getting data from the field and assign it to variable

    for item in data:
        if item['type'] == 'icmp':
            fields = item.pop('fields')
            if item['fields_under_root']:
                val.update(fields)
            else:
                nf = {}
                for k in fields:
                    nf['fields.' + k] = fields[k]
                val.update(nf)

    with open(json_filename, 'w') as fp:
        json.dump(result, fp, ensure_ascii=False)


# load data from YAML file
yaml = ruamel.yaml.YAML(typ='safe')
with open('stack.yaml') as fp:
    data = yaml.load(fp)
data2 = data.get('heartbeat.monitors')

gen_output(data2, json_name)

# show the output file
with open('stack.json') as fp:
    print(fp.read())

print('---------')
# update the YAML input file
with open('stack.yaml') as fp:
    yamlrt = ruamel.yaml.YAML() # default is round-trip, preserving comments
    data = yaml.load(fp)
data['heartbeat.monitors'][0]['fields_under_root'] = False
with open(yaml_name, 'wb') as fp:
    yamlrt.dump(data, fp)

with open('stack.yaml') as fp:
    data = yaml.load(fp)
data2 = data.get('heartbeat.monitors')

gen_output(data2, json_name)
with open('stack.json') as fp:
    print(fp.read())

给出:

{"timestamp": {"monitor.ip": "192.168.1.1", "a": "steven", "b": "kumar"}}
---------
{"timestamp": {"monitor.ip": "192.168.1.1", "fields.a": "steven", "fields.b": "kumar"}}

通用 cmets:

  • 不要测试== False== True,如果要测试is Falseis True,但最好只测试一个变量x 包含一个带有if x: 的布尔值,并且不要两者都做,一个布尔值,如果不是 TrueFalse,因此使用普通的 else:

  • 不用担心输出 JSON。无需截断,寻找 等等。只需确保您的数据格式正确,然后一次性转储即可。那 确保您的输出是有效的 JSON。

  • 不要添加 cmets 说明明显的#ip

  • 在评论标记 # 之后添加一个空格,许多 lint-ers 抱怨没有那个

  • 我在上面使用了 ruamel.yaml(免责声明:我是那个包的作者),因为与 PyYAML 以编程方式更新您的 YAML 文件会丢失您的评论信息。 因为YAML(typ='safe').load() 比 PyYAML 的 yaml.load() 快 (除了那个 PyYAML only 支持过时的 YAML 1.1)

【讨论】:

  • 感谢代码。有效。感谢您的评论。我会牢记并在未来纠正我的错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-17
  • 1970-01-01
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
  • 2012-01-21
相关资源
最近更新 更多