繁体   English   中英

如何使用python保留YAML文件中键值的顺序(不是字母顺序)

[英]How to preserve the order of Key Value in YAML file using python (not alphabetical order)

我下面有用于生成(转储)YAML文档到文件的python代码。

import yaml
import os
device_name = "NN41_R11"
ip = "10.110.11.11"
port = "2022"
def genyam():
    data  = {
         "testbed" : {
            "name"  : "boot_ios"},

        "devices"  :  {
            device_name  :  {
                "type"  : "IOS",
                "connections"  : {
                    "defaults" : {
                        "class"  :  "con.con",
                    "a"  :  {
                        "protocol" : "telnet",
                        "ip" : ip,
                        "port" : port,
                    }
                    }
                }
            }
        }
        }

    with open('/tmp/testbed.yaml', 'w') as outfile:
        yaml.dump(data, outfile, default_flow_style=False)`

生成以下YAML文件

devices:
  NN41_R11:
    connections:
      defaults:
        a:
          ip: 10.110.11.11
          port: '2022'
          protocol: telnet
        class: con.con
    type: IOS
testbed:
  name: boot_ios

尽管键值缩进是正确的,但是生成的顺序不正确。 我想先测试一下设备,然后再测试设备,但是现在相反。 我怀疑它是按字母顺序倾倒的。 NN41_R11还是一个包含type & connections的字典( typeconnections在同一级别生成,但需要第一个type:IOS并在该connections )。 基本上寻找有序的转储

生成的YAML文档应类似于以下内容:

testbed:
    name: "boot-ios"
devices:
    NN41_R11:
        type: IOS
        connections:
            defaults:
                 class: 'con.con'
            a:
              protocol: telnet
              ip: 10.110.11.11
              port: 2022

我建议您看ruamel.yaml(免责声明:我是该程序包的作者),它是专门为在加载和转储(即往返)YAML文档时保留键顺序而设计的,还可以轻松地用于生成YAML随时随地提供具有您的详细信息的文档。

您必须以某种方式在源代码中对键值对进行排序,就像在Python源代码中存在排序一样,这不会在dict保留为name data 可以使用元组列表来初始化omap类型(即ruamel.yaml.comments.CommentedMap ),但是我经常发现使用分步分配更容易。

要在不需要的字符串周围使用双引号和单引号,请使用dq (即ruamel.yaml.scalarstring.DoubleQuotedScalarString )。 sq (即ruamel.yaml.scalarstring.SingleQuotedScalarString

通过将其指定为int可以消除端口周围的引号。

import sys
import ruamel.yaml
from ruamel.yaml.comments import CommentedMap as omap
from ruamel.yaml.scalarstring import DoubleQuotedScalarString as dq
from ruamel.yaml.scalarstring import SingleQuotedScalarString as sq

yaml = ruamel.yaml.YAML()
yaml.indent(mapping=4)

device_name = "NN41_R11"
ip = "10.110.11.11"
port = 2022

def genyam():
    # initialise omap with list of tuples that are key-value-pairs
    data = omap([
        ('testbed', omap([('name', dq('boot_ios'))])),
    ])
    # or add in the order you want them in the YAML document
    data['devices'] = devices = omap()
    devices[device_name] = name = omap()
    name['type'] = 'IOS'
    name['connections'] = connections = omap()
    connections['defaults'] = omap([('class', sq('con.con')),])
    connections['a'] = a = omap()
    a['protocol'] = 'telnet'
    a['ip'] = ip
    a['port'] = port
    yaml.dump(data, sys.stdout)


genyam()

给出:

testbed:
    name: "boot_ios"
devices:
    NN41_R11:
        type: IOS
        connections:
            defaults:
                class: 'con.con'
            a:
                protocol: telnet
                ip: 10.110.11.11
                port: 2022

ruamel.yaml没有办法(在PyYAML中ruamel.yaml )无法像输出中那样获得不同映射的不同缩进(您通常有四个,五个和两个位置缩进)。


完全不同的方法是为YAML创建模板,然后加载和转储以确保它是有效的YAML(在填写模板后):

import sys
import ruamel.yaml

yaml_str = """\
testbed:
    name: "boot_ios"
devices:
    {device_name}:
        type: IOS
        connections:
            defaults:
                class: 'con.con'
            a:
                protocol: telnet
                ip: {ip}
                port: {port}
"""

yaml = ruamel.yaml.YAML()
yaml.indent(mapping=4)
yaml.preserve_quotes = True

def genyam2(device_name, ip, port):
    data = yaml.load(yaml_str.format(device_name=device_name, ip=ip, port=port))
    yaml.dump(data, sys.stdout)

genyam2(device_name = "NN41_R11", ip = "10.110.11.11", port = 2022)

它具有与上一个示例相同的输出,因为保留了往返顺序(如果您指定yaml.preseve_quotes = True ,还会保留多余的引号)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM