【问题标题】:Python YAML dump using block style without quotes使用不带引号的块样式的 Python YAML 转储
【发布时间】:2018-11-04 06:40:23
【问题描述】:

如何使用 PyYAML 加载和转储 YAML,以便它尽可能地使用原始样式?

我有 Python 来加载和转储 YAML 数据,例如:

import sys
import yaml

def _represent_dictorder(self, data):
    # Maintains ordering of specific dictionary keys in the YAML output.
    _data = []
    ordering = ['questions', 'tags', 'answers', 'weight', 'date', 'text']
    for key in ordering:
        if key in data:
            _data.append((str(key), data.pop(key)))
    if data:
        _data.extend(data.items())
    return self.represent_mapping(u'tag:yaml.org,2002:map', _data)

yaml.add_representer(dict, _represent_dictorder)

text="""-   questions:
    -   Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    tags:
        context: curabitur
    answers:
    -   weight: 2
        date: 2014-1-19
        text: |-
            1. Mauris lorem magna, auctor et tristique id, fringilla ut metus.
            2. Donec pellentesque elit non felis feugiat, in gravida ex hendrerit.
            3. Mauris quis velit sapien. Nullam blandit, diam et pharetra maximus, mi erat scelerisque turpis, eu vestibulum dui ligula non lectus.
                a. Aenean consectetur eleifend accumsan.
            4. In erat lacus, egestas ut tincidunt ac, congue quis elit. Suspendisse semper purus ac turpis maximus dignissim.
                a. Proin nec neque convallis, placerat odio non, suscipit erat. Nulla nec mattis nibh, accumsan feugiat felis.
            5. Mauris lorem magna, auctor et tristique id, fringilla ut metus.
                a. Morbi non arcu odio. Maecenas faucibus urna et leo euismod placerat.
                b. Nulla facilisi. Pellentesque at pretium nunc.
                c. Ut ipsum nibh, suscipit a pretium eu, eleifend vitae purus.
"""
yaml.dump(yaml.load(text), stream=sys.stdout, default_flow_style=False, indent=4)

但这会以不同的样式输出 YAML,例如:

-   questions:
    - Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    tags:
        context: curabitur
    answers:
    -   weight: 2
        date: 2014-1-19
        text: "1. Mauris lorem magna, auctor et tristique id, fringilla ut metus.\n\
            2. Donec pellentesque elit non felis feugiat, in gravida ex hendrerit.\n\
            3. Mauris quis velit sapien. Nullam blandit, diam et pharetra maximus,\
            \ mi erat scelerisque turpis, eu vestibulum dui ligula non lectus.\n \
            \   a. Aenean consectetur eleifend accumsan.\n4. In erat lacus, egestas\
            \ ut tincidunt ac, congue quis elit. Suspendisse semper purus ac turpis\
            \ maximus dignissim.\n    a. Proin nec neque convallis, placerat odio\
            \ non, suscipit erat. Nulla nec mattis nibh, accumsan feugiat felis.\n\
            5. Mauris lorem magna, auctor et tristique id, fringilla ut metus.\n \
            \   a. Morbi non arcu odio. Maecenas faucibus urna et leo euismod placerat.\n\
            \    b. Nulla facilisi. Pellentesque at pretium nunc.\n    c. Ut ipsum\
            \ nibh, suscipit a pretium eu, eleifend vitae purus."

如您所见,它改变了文本块的样式,因此换行符被转义,使其更难阅读。

所以我尝试指定default_style 属性,例如:

yaml.dump(yaml.load(text), stream=sys.stdout, default_flow_style=False, default_style='|', indent=4)

这修复了文本块样式,但随后通过在所有其他字符串周围加上引号、在单行字符串中添加换行符以及处理整数来破坏其他样式,例如:

-   "questions":
    - |-
        Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    "tags":
        "context": |-
            curabitur
    "answers":
    -   "weight": !!int |-
            2
        "date": |-
            2014-1-19
        "text": |-
            1. Mauris lorem magna, auctor et tristique id, fringilla ut metus.
            2. Donec pellentesque elit non felis feugiat, in gravida ex hendrerit.
            3. Mauris quis velit sapien. Nullam blandit, diam et pharetra maximus, mi erat scelerisque turpis, eu vestibulum dui ligula non lectus.
                a. Aenean consectetur eleifend accumsan.
            4. In erat lacus, egestas ut tincidunt ac, congue quis elit. Suspendisse semper purus ac turpis maximus dignissim.
                a. Proin nec neque convallis, placerat odio non, suscipit erat. Nulla nec mattis nibh, accumsan feugiat felis.
            5. Mauris lorem magna, auctor et tristique id, fringilla ut metus.
                a. Morbi non arcu odio. Maecenas faucibus urna et leo euismod placerat.
                b. Nulla facilisi. Pellentesque at pretium nunc.
                c. Ut ipsum nibh, suscipit a pretium eu, eleifend vitae purus.

如何解决这个问题,使输出类似于我原始输入的样式?

【问题讨论】:

    标签: python yaml


    【解决方案1】:

    您将如何确定将什么字符串表示为块文字(或就此而言的折叠块)以及内联表示什么?

    假设您只希望块文字与跨越多行的字符串一起使用,您可以编写自己的字符串表示器来根据字符串内容在样式之间切换:

    def selective_representer(dumper, data):
        return dumper.represent_scalar(u"tag:yaml.org,2002:str", data,
                                       style="|" if "\n" in data else None)
    
    yaml.add_representer(str, selective_representer)
    

    现在,如果您将默认流样式设置为 False 的数据转储(以防止 dict/list 内联):

    yaml.dump(yaml.load(text), stream=sys.stdout, default_flow_style=False, indent=4)
    

    您的标量将按照您的预期行事。

    【讨论】:

    • 这并没有完全解决它,但它接近了。对于包含嵌套列表的非常复杂的文本情况,它似乎仍然采用错误的样式。
    • 在进一步的测试中,我发现导致转储器转义每一行的原因是由于行只包含与外部范围的缩进不匹配的空格(例如“\n \n”)。当我用一系列换行符替换它时,问题就解决了。
    猜你喜欢
    • 2019-01-16
    • 2021-05-13
    • 2020-11-16
    • 1970-01-01
    • 1970-01-01
    • 2018-01-25
    • 2020-05-30
    • 2017-01-24
    • 2014-10-26
    相关资源
    最近更新 更多