如何使用 python(不是字母顺序)在 YAML 文件中保留键值的顺序
How to preserve the order of Key Value in YAML file using python (not alphabetical order)
我有下面的 python 代码,用于生成(转储)YAML 文档到文件。
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
的字典(type
和 connections
在同一级别生成,但首先需要 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(免责声明:我是那个包的作者),它专门设计用于在加载和转储(即 round-tripping)YAML 文档时保留键的顺序并且还可以轻松地用于动态生成包含您的详细信息的 YAML 文档。
你必须以某种方式在你的源代码中排序你的 key-value 对,尽管在 Python 源代码中有顺序,但在名称为 dict
的 dict
中没有保留=14=]。 omap
类型(即 ruamel.yaml.comments.CommentedMap
)可以用元组列表初始化,但我经常发现使用 step-by-step 赋值更容易。
要在那些不需要它的字符串周围使用双引号和单引号,请使用 dq
(即 ruamel.yaml.scalarstring.DoubleQuotedScalarString
)resp。 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 中更是如此)无法像在输出中那样为不同的映射获得不同的缩进(你大部分有四个,但也有五个和两个位置缩进) .
一种完全不同的方法是为您的 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)
这与前面的示例具有相同的输出,因为在 round-tripping 上保留了顺序(如果指定 yaml.preseve_quotes = True
,也会保留多余的引号)
我有下面的 python 代码,用于生成(转储)YAML 文档到文件。
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
的字典(type
和 connections
在同一级别生成,但首先需要 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(免责声明:我是那个包的作者),它专门设计用于在加载和转储(即 round-tripping)YAML 文档时保留键的顺序并且还可以轻松地用于动态生成包含您的详细信息的 YAML 文档。
你必须以某种方式在你的源代码中排序你的 key-value 对,尽管在 Python 源代码中有顺序,但在名称为 dict
的 dict
中没有保留=14=]。 omap
类型(即 ruamel.yaml.comments.CommentedMap
)可以用元组列表初始化,但我经常发现使用 step-by-step 赋值更容易。
要在那些不需要它的字符串周围使用双引号和单引号,请使用 dq
(即 ruamel.yaml.scalarstring.DoubleQuotedScalarString
)resp。 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 中更是如此)无法像在输出中那样为不同的映射获得不同的缩进(你大部分有四个,但也有五个和两个位置缩进) .
一种完全不同的方法是为您的 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)
这与前面的示例具有相同的输出,因为在 round-tripping 上保留了顺序(如果指定 yaml.preseve_quotes = True
,也会保留多余的引号)