【问题标题】:How can I hook a filter in PyYAML parser?如何在 PyYAML 解析器中挂钩过滤器?
【发布时间】:2017-03-28 07:25:18
【问题描述】:

我有一个要解析的 YAML 文件。

出于多种原因,我想禁止在锚点中使用点.只需在解析时将其替换为_

简单地说,我想从这里开始:

foo:
    bar.baz:
        - egg
        - spam

到那个:

foo:
    bar_baz:
        - egg
        - spam

我知道这种转换可以在生成的 Python 字典上执行,但它不是正确的地方:解析器应该抛出错误或者它应该替换有问题的值。

我已经尝试继承Loader 以进行这种转换,但似乎没有一个被覆盖的函数有任何效果。

【问题讨论】:

  • 您认为“节点名称”是什么? YAML 1.2 有节点,但根据规范它们没有名称(旧的 YAML 1.1 也是如此,这是 PyYAML 可以处理的)。您将标签称为“节点名称”还是锚点?还是您在谈论将键映射为节点名称?如果您提供一个小的示例 YAML 文件(最好是手动“转换”的版本),那就太好了。所有这些(锚点、标签、键)都可以即时更改,但需要不同的编程。
  • 已更新。问题很简单,我只是希望钩子也是。 :)
  • 即映射Node中键值对的key。 Loader 需要一个替代的 Constructor,而这并非易事。

标签: python yaml pyyaml


【解决方案1】:

没有简单的机制可以通过传递每个映射键的某个钩子的形式替换键(无论如何,您可能希望拥有更多的上下文,而不仅仅是拥有键)。 有多种方法可以解决这个问题:

  • 你可以创建一个新的Loader,它会有你自己的Constructor 子类,对映射键进行转换。这是 IMO 正确的解决方案,因为它不会影响其他 YAML 的加载。然而,这也是比较棘手的问题之一
  • 您可以为正在使用的加载程序添加一个新的映射构造函数,从而覆盖现有的构造函数。如果您不做任何特别的事情,这会影响未来所有 YAML 文件的加载。
  • 您可以包装现有的映射构造函数,加载您的 YAML 并将原始文件移回原处。这不会影响加载更多 YAML 文件。

后者可以通过以下方式完成:

import sys
import ruamel.yaml

yaml_str = """\
foo:
    bar.baz:
        - egg
        - spam
"""


def alt_construct_mapping(self, *args, **kw):
    """replace keys with dot"""
    m = self.org_construct_mapping(*args, **kw)
    for k in m:
        if '.' in k:
            m[k.replace('.', '_')] = m.pop(k)
    return m

# backup up the constructor
ruamel.yaml.constructor.BaseConstructor.org_construct_mapping = \
    ruamel.yaml.constructor.BaseConstructor.construct_mapping

# replace the constructor
ruamel.yaml.constructor.BaseConstructor.construct_mapping = alt_construct_mapping


data = ruamel.yaml.safe_load(yaml_str)
ruamel.yaml.round_trip_dump(data, sys.stdout)

# put original constructor back
ruamel.yaml.constructor.BaseConstructor.construct_mapping = \
    ruamel.yaml.constructor.BaseConstructor.org_construct_mapping

给出:

foo:
  bar_baz:
  - egg
  - spam

这是使用 ruamel.yaml 完成的,它是 PyYAML 的增强版本,我是它的作者。对于 PyYAML,只要您的 YAML 没有任何 YAML 版本 1.2 结构,这应该可以正常工作,将 ruamel.yaml 替换为 yaml 并将 round_trip_load/dump 替换为 safe_load/dump

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-04-06
    • 2019-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-02
    • 1970-01-01
    相关资源
    最近更新 更多