【问题标题】:How can I parse YAML into multiple compose.yaml based on the value of a key with python如何根据 python 键的值将 YAML 解析为多个 compose.yaml
【发布时间】:2019-08-22 06:51:04
【问题描述】:

我正在解析 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】:

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

    另请注意,您的输出是无效的 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
    

    【讨论】:

    • 非常感谢!我有另一个问题。如果我想使用 DoubleQuotedScalarString(connect(while is a is a CommentedMap instance)),结果是 "ordereddict([('test1', 10), ('test2', 'abc'), ('test3', ' def')])" 如何清除“ordereddict”并保持键值对有序?使用dict可以清除,但是key-value对是无序的。
    • 如果这回答了您的问题,请点击答案旁边的复选标记 (✓) 接受它。这样其他人就知道它得到了回答。至于您评论中的问题,我不确定您清楚orderdict 并按顺序保留键值对。您可以将键值对复制到字典中,该字典在 Python 3.7(3.6?)中按插入顺序排列,但缺少完整有序字典中的一些功能。
    猜你喜欢
    • 2018-04-27
    • 1970-01-01
    • 1970-01-01
    • 2021-03-13
    • 1970-01-01
    • 2015-12-31
    • 2014-12-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多