yaml使用键或父键作为值
我刚刚开始使用YAML(通过pyyaml),我想知道是否有任何方法可以声明键的值是键名本身还是父键。 比如说yaml使用键或父键作为值,yaml,pyyaml,Yaml,Pyyaml,我刚刚开始使用YAML(通过pyyaml),我想知道是否有任何方法可以声明键的值是键名本身还是父键。 比如说 --- foo: &FOO bar: !. baz: !.. foo2: <<: *FOO … {‘foo’: {‘bar’: ‘bar’, ‘baz’: ’foo’}, ‘foo2’:{‘bar’:’bar’, ‘baz’:’foo2’}} 但是Node不持有密钥(或父节点的引用),我无法找到获取它们的方法 编辑: 下面是我的真实用例和基于Anth
---
foo: &FOO
bar: !.
baz: !..
foo2:
<<: *FOO
…
{‘foo’: {‘bar’: ‘bar’, ‘baz’: ’foo’}, ‘foo2’:{‘bar’:’bar’, ‘baz’:’foo2’}}
但是Node不持有密钥(或父节点的引用),我无法找到获取它们的方法
编辑:
下面是我的真实用例和基于Anthon回应的解决方案:
我有一个记录器配置文件(在yaml中),我想重用其中的一些定义:
handlers:
base: &base_handler
(): globals.TimedRotatingFileHandlerFactory
name: ../
when: midnight
backupCount: 14
level: DEBUG
formatter: generic
syslog:
class: logging.handlers.SysLogHandler
address: ['localhost', 514]
facility: local5
level: NOTSET
formatter: syslog
access:
<<: *base_handler
error:
<<: *base_handler
loggers:
base: &base_logger
handlers: [../, syslog]
qualname: ../
access:
<<: *base_logger
error:
<<: *base_logger
handlers: [../, syslog, email]
在构造元素时,您没有太多的上下文,因此如果不挖掘上下文的调用堆栈,就无法找到填充值的键,当然也无法找到父键(加载程序
知道foo
、bar
和baz
,但不能用于确定哪个是对应的键或父键)
我建议您创建一个特殊的节点,使用key\u construct
返回该节点,然后在YAML加载之后,遍历您的YAML.load()结构
返回。除非您有其他!
对象,这些对象使得遍历结果组合比单纯的序列/列表和映射/dicts组合更困难,否则:
import ruamel.yaml as yaml
yaml_str = """\
foo: &FOO
bar: !.
baz: !..
foo2:
<<: *FOO
"""
class Expander:
def __init__(self, tag):
self.tag = tag
def expand(self, key, parent_key):
if self.tag == '!.':
return key
elif self.tag == '!..':
return parent_key
raise NotImplementedError
def __repr__(self):
return "E({})".format(self.tag)
def expand(d, key=None, parent_key=None):
if isinstance(d, list):
for elem in d:
expand(elem, key=key, parent_key=parent_key)
elif isinstance(d, dict):
for k in d:
v = d[k]
if isinstance(v, Expander):
d[k] = v.expand(k, parent_key)
expand(d[k], key, parent_key=k)
return d
def key_construct(loader, node):
return Expander(node.tag)
yaml.add_constructor('!.', key_construct)
yaml.add_constructor('!..', key_construct)
data = yaml.load(yaml_str)
print(data)
print(expand(data))
这是使用我是作者的方法完成的。PyYAML,其中ruamel.yaml是一个功能超集,应该也可以使用它。这可能是一个剪切和粘贴错误,但是unicode字符2026,就像在源代码中一样,会给你一个扫描错误。你可能是指..
而不是..
。但一般来说,这些字符的开头和结尾都是f文档标记对于单个文档文件不是必需的。谢谢@Anthon,我实际上没有使用它们。我添加它们是为了清晰(区分代码和结果)谢谢@Anthon。如果我需要遍历结构,那么其他东西不是多余的吗?(添加构造函数并展开)我可以简单地删除感叹号并检查字符串值中的“.”或“.”。不过,我真希望有另一种方法。一种不需要再次遍历结构的方法,但我想我只能忍受这几毫秒的浪费:)@只有当您不希望任何字符串标量应该是
或时,它才是多余的。
。如果你能接受这一点,你确实可以将整个过程简化为expande()
function()。如果你想在不重新转换的情况下实现这一点,你需要更新解析器,以便在启动/结束新映射时,将当前键值的槽添加到某个堆栈中,这是比较容易的部分。如果您还希望使用定位点和别名,则需要使用定位点定义存储堆栈。我看到了这一点,当然这是可能的,但作为一个答案,“只是实施”的可能性很大
def expand_yaml(val, parent=None, key=None, key1=None, key2=None):
if isinstance(val, str):
if val == './':
parent[key] = key1
elif val == '../':
parent[key] = key2
elif isinstance(val, dict):
for k, v in val.items():
expand_yaml(v, val, k, k, key1)
elif isinstance(val, list):
parent[key] = val[:] # support inheritance of the list (as in *base_logger)
for index, e in enumerate(parent[key]):
expand_yaml(e, parent[key], index, key1, key2)
return val
import ruamel.yaml as yaml
yaml_str = """\
foo: &FOO
bar: !.
baz: !..
foo2:
<<: *FOO
"""
class Expander:
def __init__(self, tag):
self.tag = tag
def expand(self, key, parent_key):
if self.tag == '!.':
return key
elif self.tag == '!..':
return parent_key
raise NotImplementedError
def __repr__(self):
return "E({})".format(self.tag)
def expand(d, key=None, parent_key=None):
if isinstance(d, list):
for elem in d:
expand(elem, key=key, parent_key=parent_key)
elif isinstance(d, dict):
for k in d:
v = d[k]
if isinstance(v, Expander):
d[k] = v.expand(k, parent_key)
expand(d[k], key, parent_key=k)
return d
def key_construct(loader, node):
return Expander(node.tag)
yaml.add_constructor('!.', key_construct)
yaml.add_constructor('!..', key_construct)
data = yaml.load(yaml_str)
print(data)
print(expand(data))
{'foo': {'bar': E(!.), 'baz': E(!..)}, 'foo2': {'bar': E(!.), 'baz': E(!..)}}
{'foo': {'bar': 'bar', 'baz': 'foo'}, 'foo2': {'bar': 'bar', 'baz': 'foo2'}}