我正在用 Python 编辑一个带有大量锚点和别名的大型 YAML 文档。我希望能够根据来自它引用的节点的数据来确定锚是如何派生的。
例如,节点有一个“名称”字段,我希望锚点是该字段的值,而不是随机的 id 号。
PyYAML 或 ruamel.yaml 可以做到这一点吗?
我正在用 Python 编辑一个带有大量锚点和别名的大型 YAML 文档。我希望能够根据来自它引用的节点的数据来确定锚是如何派生的。
例如,节点有一个“名称”字段,我希望锚点是该字段的值,而不是随机的 id 号。
PyYAML 或 ruamel.yaml 可以做到这一点吗?
有几件事情要记住:
name
'的值相同name
”的值了。dump
-ing 期间创建的,因此在使用 PyYAML 时必须挂钩。你可以这样做ruamel.yaml
ruamel.yaml
具有在往返过程中保留锚点的能力。即,如果您可以使锚点保持不变,即使键 ' name
' 的值发生变化(假设您在默认生成的表单上进行测试idNNNN
)当您使用时,ruamel.yaml
您可以递归地遍历数据结构,跟踪已经访问过的节点(如果子节点包含祖先),当遇到 a 时ruamel.yaml.comments.CommentedMap
,设置锚点(当前值为ruamel.yaml.comments.Anchor.attrib
ie的属性_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
s 实际上都是CommentedMap
s 在引擎盖下。如果不是这种情况(即您添加了正常dict
的 s,则取消注释进行转换的两行。