如何根据python的键值将YAML解析为多个compose.yaml

问题描述 投票:1回答:1

我正在解析YAML并将其分解为多个不同的YAML文件。我使用PyYAML的构造函数来实现它,但效果很差。

这是我项目的一部分,我需要根据我收到的yaml文件中的键值解析并拆分成多个不同的yaml文件。

我收到的yaml文件看起来像这样

testname: testname
testall:
    test1:
        name: name1
        location: 0
    test2: 
        name: name2
        location: 2
    test3: 
        name: name3
        location: 0
    test4: 
        name: name4
        location: 2
    ...
locations:
    - 0
    - 2
    - ...  

我想解析它并按设备拆分如下:

# location0.yaml
testname:test
tests:
    test1:
        name:test1
        location:0
    test3: 
        name: test3
        location: 0
# location2.yaml
testname:test
tests:
    test2:
        name:test2
        location:0
    test4: 
        name: test4
        location: 0

如何解析上面的表格?

python-3.x yaml pyyaml ruamel.yaml
1个回答
0
投票

虽然您可以使用PyYAML执行此操作,但您必须将自己限制为YAML 1.1。对于这种读 - 修改 - 写,你应该使用ruamel.yaml(免责声明:我是该包的作者)。这不仅支持YAML 1.2,它还会保留任何注释,标签和锚名称,以防它们出现在源代码中,并且如果需要,可以保留标量,文字和折叠样式等的引号。

另请注意,您的输出是无效的YAML,您不能将多行普通(即未引用)标量作为(块样式)映射的关键。你必须写:

"testname:test
tests":

但我认为你的意思是成为根级映射的两个键:

testname: test
tests:

假设你的输入是在input.yaml

testname: testname
testall:
    test1:
        name: name1    # this is just the first name
        location: 0
    test2: 
        name: "name2"  # quotes added for demo purposes
        location: 2
    test3: 
        name: name3    # as this has the same location as name1 
        location: 0    # these should be together
    test4: 
        name: name4    # and this one goes with name2
        location: 2
locations:
    - 0
    - 2

你可以做:

import sys
from pathlib import Path
import ruamel.yaml

in_file = Path('input.yaml')


yaml = ruamel.yaml.YAML()
yaml.indent(mapping=4, sequence=6, offset=4)  # this matches your input
yaml.preserve_quotes = True
data = yaml.load(in_file)

for loc in data['locations']:
    out_name = f'location{loc}.yaml'
    tests = {}
    d = ruamel.yaml.comments.CommentedMap(dict(testname="test", tests=tests))
    d.yaml_set_start_comment(out_name)
    testall = data['testall']
    for test in testall:
        if loc == testall[test]['location']:
           tests[test] = testall[test]
           tests[test]['location'] = 0
    # since you set location to zero and this affects data, make sure to remove 
    # the items. This will prevent things from going wrong in case the
    # locations sequence does have zero, but not as its first number
    for key in tests:
         del testall[key]
    yaml.dump(d, Path(out_name))

location0.yaml

# location0.yaml
testname: test
tests:
    test1:
        name: name1    # this is just the first name
        location: 0
    test3:
        name: name3    # as this has the same location as name1 
        location: 0    # these should be together

location2.yaml

# location2.yaml
testname: test
tests:
    test2:
        name: "name2"  # quotes added for demo purposes
        location: 0
    test4:
        name: name4    # and this one goes with name2
        location: 0
© www.soinside.com 2019 - 2024. All rights reserved.