2016-11-20 29 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

相關問題