[PyYAML标准标记的替代构造函数

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

[尝试创建能够扩展变量的加载程序时,我注意到当我使用块标量(例如>-)时,PyYAML并未扩展变量。因此,举个例子:

# ademo.yml
key1: foo
key2: bar $LOL bar
key3: >-
    baz $ASD baz

为了展开变量,我做了以下操作:

# yaamer.py
import re
import sys
import yaml

# I create a loder
class MyLoader(yaml.SafeLoader): pass

# Add to it an implicit resolver that matches variables
matcher = re.compile(r".*\$[A-Z].*")
MyLoader.add_implicit_resolver("!path", matcher, None)

# Add a constructor that would replaces the variable
def cons(loader, node):
    print("Constructing for", node)
    return "FOO"
MyLoader.add_constructor("!path", cons)

with open(sys.argv[1]) as inf:
    print(yaml.load(inf, MyLoader))

[当我打电话给它时,python yaamer.py ademo.yml,我得到这个输出:

Constructing for ScalarNode(tag='!path', value='bar $LOL bar')
{'key1': 'foo', 'key2': 'FOO', 'key3': 'baz $ASD baz'}

因此,替换项仅在key2中,而不在key3中。

为了了解正在发生的事情,我为正则表达式实现了一个包装,让我了解发生了什么:

class Matcher:
    def __init__(self):
        self.matcher = re.compile(r".*\$[A-Z].*")                                                                 
    def match(self, *args, **kwargs):
        print("Matching", args, kwargs)
        return self.matcher.match(*args, **kwargs)

并使用它会导致此输出:

Matching ('key1',) {}
Matching ('foo',) {}
Matching ('key2',) {}
Matching ('bar $LOL bar',) {}
Matching ('key3',) {}
Constructing for ScalarNode(tag='!path', value='bar $LOL bar')
{'key1': 'foo', 'key2': 'FOO', 'key3': 'baz $ASD baz'}

在比赛中没有块标量的痕迹!因此,显然,此匹配器从未用于解析>-块。

因此,我进行了调查,发现有一些pre-defined tags,例如!!str!!map。不过,由于>-是一种特殊的语法,因此它会自动与这些标签之一匹配。

所以我继续为所有标签安装自定义构造函数,以查看是否调用了其中的任何一个:

def make_cons(name):
    def _cons(loader, node):
        print("Constructor for", name)
        return node.value
    return _cons

MyLoader.add_constructor("!!str", make_cons('!!str'))
MyLoader.add_constructor("!!int", make_cons('!!int'))

但是它们被从不叫!到底是怎么回事??如果我必须为现有的YAML标签安装自定义构造函数,该怎么办?

python yaml pyyaml
1个回答
0
投票

隐式解析器只能匹配普通标量,不带引号。带引号的意思是单引号或双引号,或者字面量或折叠块标量。因此,您的key3是折叠块标量,因此不考虑匹配。

您可以在YAML源代码中向其显式添加!path标记,然后将调用您的自定义构造函数。

请参见PyYAML Documentation,并查找单词“隐式”和“普通”。

要为标准标记添加构造函数,您需要使用全名。 !!str只是tag:yaml.org,2002:str的简写:

yaml.add_constructor('tag:yaml.org,2002:str', my_constructor)
© www.soinside.com 2019 - 2024. All rights reserved.