【问题标题】:YAML parsing with comments for doc purpose用于文档目的的带有注释的 YAML 解析
【发布时间】:2019-08-03 10:23:26
【问题描述】:

我需要在 YAML 上添加 cmets 以自动构建我的 YAML 文件的文档,就像 Python 的文档字符串一样。

所以我正在寻找一个 Python 解析器,它能够:

  • 尊重对象的顺序
  • 包括 cmets

我的研究将我指向 ruamel.yaml。但除非我没有得到所有东西,否则在加载 cmets 时它不允许访问 YAML 对象。它只允许在加载期间转储该 cmets。

你知道,什么可以满足我的需求?

【问题讨论】:

  • 嗯,YAML 文件只是一个文本文件,带有一些缩进。将其解析为文本文件,一切顺利。
  • @ryguy72 注释在 YAML 中由空格后跟 # 引入,但此序列可以作为标量的一部分出现,例如如果该标量被引用,或者是多行标量。因此,提取 cmets 并仅提取 cmets 并不像您说的那么简单。

标签: python ansible yaml ruamel.yaml


【解决方案1】:

ruamel.yaml 中,YAML() 实例仅将信息保存到 分别加载转储您的 YAML 文档。 它不允许您访问 cmets,因为它不会将它们存储在实例中

正如您所指出的,ruamel.yaml 可以转储 cmets,因此他们必须 在某个地方,它们确实是:附加到对象层次结构中 由YAML.load() 创建。而你需要做的是递归地走 为获取附加的 cmets 而加载的数据结构。

对于当前连接 cmets 的方式,如下所示:

import sys
import ruamel.yaml
from ruamel.yaml.tokens import CommentToken

yaml_str = """\
a:
  b:
  - elem1   # this is the first comment
  - elem2   # this is the second comment
  c:
    d: 42   # this is not the 42nd comment  
"""

def extract_from_token(tl):
    assert isinstance(tl, list)
    for t in tl:
        if t is None:
            continue
        yield t.start_mark.line, t.value

def get_yaml_comments(d):
    if isinstance(d, dict):
        if d.ca.comment is not None:
            for l, c in extract_from_token(d.ca.comment):
                yield l, c
        for key, val in d.items():
            for l, c in get_yaml_comments(val):
                yield l, c
            if key in d.ca.items:
                for l, c in extract_from_token(d.ca.items[key]):
                    yield l, c
    elif isinstance(d, list):
        if d.ca.comment is not None:
            for l, c in extract_from_token(d.ca.comment):
                yield l, c
        for idx, item in enumerate(d):
            for l, c in get_yaml_comments(item):
                yield l, c
            if idx in d.ca.items:
                for l, c in extract_from_token(d.ca.items[idx]):
                    yield l, c


yaml = ruamel.yaml.YAML()
data = yaml.load(yaml_str)

for line, comment in get_yaml_comments(data):
    print(f"{comment!r} ({line})")

给出:

'# this is the first comment\n' (2)
'# this is the second comment\n' (3)
'# this is not the 42nd comment  \n' (5)

【讨论】:

  • 抱歉回复晚了,感谢您的回复。它按照你说的做,它打印出一个 yaml 字符串的 cmets。但我正在寻找的是略有不同。我想提取 cmets 和 yaml 部分。我不是特别想在结构中提取嵌入的注释。所以我想得到一个列表 [comment, yaml, comment, yaml...]。我不明白为什么这样做如此复杂,为什么没有记录在案。
  • 您应该更新您的问题,因为您在评论中描述的内容在您的帖子中完全不清楚。当然,我无法记录如何通过按下一个按钮来完成世界上每个人(显然很少有人)想要做的事情,但是当你认为这很容易时,请随意实施。只需提供 PR,包括文档。
  • 我对如何获得您在评论中描述的内容有一个好主意,但是由于我可能会使它变得复杂,我将等待您自己提出简单解决方案的 PR .
  • lol Anthon... 不,我很生气自己不能按照你的建议去做我想做的事。这与您的解决方案无关。我想说的是,遗憾的是 ruamel 模块没有为此提供更简单的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-24
  • 1970-01-01
  • 2012-01-04
  • 2018-10-15
  • 2016-01-12
  • 2012-07-28
  • 2021-05-03
相关资源
最近更新 更多