是否可以在跨所有文档的多文档 YAML 流中使用别名?
Is it possible to have aliases in a multi-document YAML stream that span all documents?
这就是我想要做的(代码在 Python 3 中):
import ruamel.yaml as yaml
from print import pprint
yaml_document_with_aliases = """
title: test
choices: &C
a: one
b: two
c: three
---
title: test 2
choices: *C
"""
items = list(yaml.load_all(yaml_document_with_aliases))
结果是:
ComposerError: found undefined alias 'C'
当我使用非基于文档的 YAML 文件时,这按预期工作:
import ruamel.yaml as yaml
from print import pprint
yaml_nodes_with_aliases = """
-
title: test
choices: &C
a: one
b: two
c: three
-
title: test 2
choices: *C
"""
items = yaml.load(yaml_nodes_with_aliases)
pprint(items)
结果:
[{'choices': {'a': 'one', 'b': 'two', 'c': 'three'}, 'title': 'test'},
{'choices': {'a': 'one', 'b': 'two', 'c': 'three'}, 'title': 'test 2'}]
(无论如何我想完成的)
由于现在不可能,我正在使用以下脆弱的解决方法:
def yaml_load_all_with_aliases(yaml_text):
if not yaml_text.startswith('---'):
yaml_text = '---\n' + yaml_text
for pat, repl in [('^', ' '), ('^\s*---\s*$', '-'), ('^\s+\.{3}$\n', '')]:
yaml_text = re.sub(pat, repl, yaml_text, flags=re.MULTILINE)
yaml_text = yaml_text.strip()
return yaml.safe_load(yaml_text)
这里的问题是:
title: test
choices: &C
a: one
b: two
c: three
---
title: test 2
choices: *C
不是一个文件,这是一个文件中的两个YAML文件。锚点定义 &C
不会从一个 YAML 文档携带到另一个 YAML 文档,它只能用到文档分隔符 ---
.
如果您愿意将所有锚 "carry over" 指向单个 YAML 流中的以下文档,您可以在 Composer
class 上移植一个新的 compose_document
方法(即猴子补丁):
import sys
import ruamel.yaml
yaml_str = """\
title: test
choices: &C
a: one
b: two
c: three
---
title: test 2
choices: *C
"""
def my_compose_document(self):
self.get_event()
node = self.compose_node(None, None)
self.get_event()
# this prevents cleaning of anchors between documents in **one stream**
# self.anchors = {}
return node
ruamel.yaml.composer.Composer.compose_document = my_compose_document
datas = []
for data in ruamel.yaml.safe_load_all(yaml_str):
datas.append(data)
datas[0]['choices']['a'] = 1
for data in datas:
ruamel.yaml.round_trip_dump(data, sys.stdout, explicit_start=True)
给出:
---
title: test
choices:
a: 1
b: two
c: three
---
title: test 2
choices:
a: one
b: two
c: three
请注意,这会为您提供 副本 的字典,键为 a
、b
和 c
。
(如果键排序和注释保存很重要,请使用 round_trip_load_all
而不是 safe_load_all
)
这就是我想要做的(代码在 Python 3 中):
import ruamel.yaml as yaml
from print import pprint
yaml_document_with_aliases = """
title: test
choices: &C
a: one
b: two
c: three
---
title: test 2
choices: *C
"""
items = list(yaml.load_all(yaml_document_with_aliases))
结果是:
ComposerError: found undefined alias 'C'
当我使用非基于文档的 YAML 文件时,这按预期工作:
import ruamel.yaml as yaml
from print import pprint
yaml_nodes_with_aliases = """
-
title: test
choices: &C
a: one
b: two
c: three
-
title: test 2
choices: *C
"""
items = yaml.load(yaml_nodes_with_aliases)
pprint(items)
结果:
[{'choices': {'a': 'one', 'b': 'two', 'c': 'three'}, 'title': 'test'},
{'choices': {'a': 'one', 'b': 'two', 'c': 'three'}, 'title': 'test 2'}]
(无论如何我想完成的)
由于现在不可能,我正在使用以下脆弱的解决方法:
def yaml_load_all_with_aliases(yaml_text):
if not yaml_text.startswith('---'):
yaml_text = '---\n' + yaml_text
for pat, repl in [('^', ' '), ('^\s*---\s*$', '-'), ('^\s+\.{3}$\n', '')]:
yaml_text = re.sub(pat, repl, yaml_text, flags=re.MULTILINE)
yaml_text = yaml_text.strip()
return yaml.safe_load(yaml_text)
这里的问题是:
title: test
choices: &C
a: one
b: two
c: three
---
title: test 2
choices: *C
不是一个文件,这是一个文件中的两个YAML文件。锚点定义 &C
不会从一个 YAML 文档携带到另一个 YAML 文档,它只能用到文档分隔符 ---
.
如果您愿意将所有锚 "carry over" 指向单个 YAML 流中的以下文档,您可以在 Composer
class 上移植一个新的 compose_document
方法(即猴子补丁):
import sys
import ruamel.yaml
yaml_str = """\
title: test
choices: &C
a: one
b: two
c: three
---
title: test 2
choices: *C
"""
def my_compose_document(self):
self.get_event()
node = self.compose_node(None, None)
self.get_event()
# this prevents cleaning of anchors between documents in **one stream**
# self.anchors = {}
return node
ruamel.yaml.composer.Composer.compose_document = my_compose_document
datas = []
for data in ruamel.yaml.safe_load_all(yaml_str):
datas.append(data)
datas[0]['choices']['a'] = 1
for data in datas:
ruamel.yaml.round_trip_dump(data, sys.stdout, explicit_start=True)
给出:
---
title: test
choices:
a: 1
b: two
c: three
---
title: test 2
choices:
a: one
b: two
c: three
请注意,这会为您提供 副本 的字典,键为 a
、b
和 c
。
(如果键排序和注释保存很重要,请使用 round_trip_load_all
而不是 safe_load_all
)