我在Python中编辑了一个包含大量锚点和别名的大型YAML文档。我希望能够根据它引用的节点的数据确定锚的派生方式。
例如,节点有一个'名称'字段,我希望锚点是该字段的值,而不是随机的id号。
PyYAML或ruamel.yaml可以实现吗?
答案 0 :(得分:3)
有几点需要注意:
name
”的值相同name
”的值。 dump
期间创建,因此在使用PyYAML时必须挂钩。您可以使用ruamel.yaml
ruamel.yaml
才能在往返时保留锚点。即如果您可以让锚定为持久性,即使密钥“name
”的值发生更改(假设您在默认生成的表单idNNNN
上进行测试)使用ruamel.yaml
时,您可以递归遍历数据结构,跟踪已访问的节点(如果子项包含祖先),遇到ruamel.yaml.comments.CommentedMap
时,设置锚点(当前值为ruamel.yaml.comments.Anchor.attrib
的属性,即_yaml_anchor
)。未经测试的代码:
if isinstance(x, ruamel.yaml.comments.CommentedMap):
if 'name' in x:
x.yaml_set_anchor(x['name'])
如果您有可以往返的YAML文件,您可以挂钩代表:
import sys
import ruamel.yaml
from ruamel.yaml.representer import RoundTripRepresenter
yaml_str = """\
# data = [dict(a=1, b=2, name='mydata'), dict(c=3)]
# data.append(data[0])
- &id001
a: 1
b: 2
name: mydata
- c: 3
- *id001
"""
class MyRTR(RoundTripRepresenter):
def represent_mapping(self, tag, mapping, flow_style=None):
if 'name' in mapping:
# if not isinstance(mapping, ruamel.yaml.comments.CommentedMap):
# mapping = ruamel.yaml.comments.CommentedMap(mapping)
mapping.yaml_set_anchor(mapping['name'])
mapping.yaml_set_anchor(mapping['name'])
return RoundTripRepresenter.represent_mapping(
self, tag, mapping, flow_style=flow_style)
yaml = ruamel.yaml.YAML()
yaml.Representer = MyRTR
data = yaml.load(yaml_str)
yaml.dump(data, sys.stdout)
给出:
# data = [dict(a=1, b=2, name='mydata'), dict(c=3)]
# data.append(data[0])
- &mydata a: 1
b: 2
name: mydata
- c: 3
- *mydata
但请注意,这假设您加载了数据,并且所有dict
实际上都是CommentedMap
。如果不是这种情况(即您添加了正常dict
s,则取消注释进行转换的两行。