2016-11-20 89 views
1

这就是我想要做的(代码在Python 3):是否可以在跨文档的多文档YAML流中使用别名?

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) 
+0

你应该使用'safe_load_all()'和'safe_load()'除非你在真正的文件已标记YAML内容。这不会解决找不到锚的问题,但它会阻止潜在的恶意YAML在您的程序中执行任意代码 – Anthon

回答

1

这里的问题是:

title: test 
choices: &C 
    a: one 
    b: two 
    c: three 
--- 
title: test 2 
choices: *C 

不是a文件,这些是两个YAML文件中的一个文件。锚定义&C不从一个YAML文档携带到另一个,它只能用到文档分隔符---

如果你愿意把所有锚“结转”下列文件中的一个YAML流,你可以在Composer类(即猴子补丁吧)移植了新的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 

注意,这让你有钥匙ab,并c的字典的副本

(如果该键排序和评论保存是重要的,使用的round_trip_load_all代替safe_load_all

+0

首先,感谢回答这么快:) 原谅我,我以为我有术语权......那么你打电话的时候是什么?多文档? (最重要的是)是否没有办法将别名定义从一个文档转移到另一个文档? – gschizas

+0

@gschizas YAML 1.2讨论文档和流,后者可以有多个(或一个或零个)文档。 ('safe_')'load_all'用于迭代文档。在正常的加载器中,当YAML被组合到本地数据结构中时,锚和别名信息被解析[**和丢弃**](http://yaml.org/spec/1.2/spec.html#id2765878)。随着往返加载你可能能够从一个文件记录到另一个,因为在这种情况下,锚信息不会被丢弃(我正在研究,这不是微不足道的) – Anthon

+0

谢谢 - 我认为这是一些东西我错过了,或者需要比我自己能处理更多的事情。现在我已经使用了一个愚蠢而脆弱的解决方法。 – gschizas

相关问题