使用Python在YAML中保留锚点和别名
我正在用Python编辑一个带有大量锚和别名的大型YAML文档。我希望能够根据它引用的节点的数据来确定锚点是如何派生的 例如,节点有一个“name”字段,我希望锚点是该字段的值,而不是随机id号使用Python在YAML中保留锚点和别名,python,yaml,cross-reference,ruamel.yaml,Python,Yaml,Cross Reference,Ruamel.yaml,我正在用Python编辑一个带有大量锚和别名的大型YAML文档。我希望能够根据它引用的节点的数据来确定锚点是如何派生的 例如,节点有一个“name”字段,我希望锚点是该字段的值,而不是随机id号 Pyaml或ruamel.yaml是否可能实现这一点?有几点需要记住: YAML没有字段。我假设这是您对映射中键的解释,因此您希望与映射关联的锚点与键“name”的值相同 在加载期间,遇到锚点时创建的事件不知道它是标量、序列还是映射上的锚点。更不用说它可以访问“name”的值了 在加载期间更改锚点很棘
Pyaml或ruamel.yaml是否可能实现这一点?有几点需要记住:
- YAML没有字段。我假设这是您对映射中键的解释,因此您希望与映射关联的锚点与键“
”的值相同name
- 在加载期间,遇到锚点时创建的事件不知道它是标量、序列还是映射上的锚点。更不用说它可以访问“
”的值了李>name
- 在加载期间更改锚点很棘手,因为您必须跟踪引用原始锚点的别名(并将其映射到其新值)
- 在PyYAML中,锚点名称是在
-ing过程中创建的,因此在使用PyYAML时必须钩住锚点名称。您也可以使用dump
ruamel.yaml
- 只有
能够在往返途中保留锚。也就是说,即使键“ruamel.yaml
”的值发生变化(假设您在默认生成的表单name
上进行测试),您也可以使锚保持不变idNNNN
ruamel.yaml
时,可以递归遍历数据结构,跟踪已访问的节点(如果子节点包含祖先),当遇到ruamel.yaml.comments.CommentedMap
时,设置锚点(当前属性的值为ruamel.yaml.comments.Anchor.attrib
即\u yaml\u Anchor
)。未测试代码:
if isinstance(x, ruamel.yaml.comments.CommentedMap):
if 'name' in x:
x.yaml_set_anchor(x['name'])
如果您有一个YAML文档可以往返,您可以挂接到representer:
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(即,您添加了normaldict
s,然后取消对进行转换的两行的注释。锚点是如何派生的,这是什么意思?转储数据结构时,PyYAML和ruamel.yaml检查特定的复杂对象(即不是像整数、字符串这样的原始对象)已转储并创建别名(如果已转储)。ruamel.yaml所做的一件事是将原始锚点名称附加到该复杂结构,以便它可以重用它。但是没有引用列表,有一个对象具有通过数据结构到该对象的多条路径。您必须遍历树才能找到所有引用就像翻车机一样。谢谢你的解释。我希望能够在初始负载上修改锚。这只有通过查看事件级别才能实现吗?谢谢你,这是一个非常详细的答案,有助于了解我想要的东西是否可行。也感谢你在ruamel.yaml上的工作。