2017-02-11 201 views
2

我需要爲YAML文件中的現有密鑰添加額外的值。以下是我正在使用的代碼。使用ruamel.yaml修改YAML會添加額外的新行

with open(yaml_in_path, 'r') as f: 
    doc, ind, bsi = load_yaml_guess_indent(f, preserve_quotes=True) 
doc['phase1'] += ['c'] 
with open(yaml_out_path, 'w') as f: 
    ruamel.yaml.round_trip_dump(doc, f, 
           indent=2, block_seq_indent=bsi) 

這是輸入和輸出。

輸入

phase1: 
    - a 
    # a comment. 
    - b 

phase2: 
    - d 

輸出

phase1: 
    - a 
    # a comment. 
    - b 

    - c 
phase2: 
    - d 

如何才能擺脫bc之間的新生產線的? (當phase1是文件中的唯一密鑰或phase1phase2之間沒有空行時,此問題不存在)。

回答

0

這裏的問題是,空行被認爲是排序的評論, ruamel.yaml中的註釋通過將它們與序列中的元素或映射中的鍵關聯來保留。該值存儲在名爲ca的複合屬性中,該對象與第二個元素關聯的對象doc['phase1']一樣。

你當然可以爭辯說它應該與最高級別的映射/字典關聯,或者與關鍵字phase1(作爲一些最終的空行評論)關聯,或者與phase2關聯作爲一些介紹性的空行評論。 以上三者中的任何一個都是有效的,並且目前在圖書館中沒有控制策略,其中空行(或註釋發生)。

如果你把一個「真正」的評論(一個開始#)它phase1相關聯作爲最終意見,對於那些策略是不同的。

這顯然需要檢修,爲ruamel.yaml原來的目標是: - 從YAML 加載一些配置 - 改變一些值 - 將配置保存到YAML 在這種情況下,這些類型的附加的/插入的問題不要」 t出現。

因此,直到擴展庫並控制附加(尾隨)註釋和/或空行的位置時纔有真正的解決方案。

在此之前控制得到實施,可能是你能做的最好的事情是:

import sys 
import ruamel.yaml 

yaml_str = """\ 
phase1: 
    - a 
    # a comment. 
    - b 

phase2: 
    - d 
""" 

def append_move_comment(l, e): 
    i = len(l) - 1 
    l.append(e) 
    x = l.ca.items[i][0] # the end comment 
    if x is None: 
     return 
    l.ca.items[i][0] = None 
    l.ca.items[i+1] = [x, None, None, None] 

data = ruamel.yaml.round_trip_load(yaml_str) 
append_move_comment(data['phase1'], 'c') 
ruamel.yaml.round_trip_dump(data, sys.stdout, indent=4, block_seq_indent=2) 

我改變了indent值4,這是你的輸入有(和得到,因爲你將它指定爲對於block_seq_indent爲小)。

+0

感謝您的支持。你能解釋一下在分配[x,None,None,None]而不是[x]後面的推理嗎?我在哪裏可以查看ruamel.yaml的源代碼以瞭解此數據結構? – keheliya

+0

我不知道如果我在所有情況下都正確地檢查了它的長度,你可能會少一些,但我不會嘗試。這不是故意記錄的,因爲它可以在將來的版本中更改。 'ca'屬性是'ruamel.yaml.comments.Comment()'的一個實例,'x'是'ruamel.yaml.tokens.CommentToken()'。提示:如果沒有人問你,請使用'print(type(l.ca),'\ n',type(x))';-)。 – Anthon

+0

嘿@安徒生,我剛剛偶然發現了這個同樣的問題。自發布此答案以來有任何更新的機會?現在可以用更優雅的方式避免這種情況了嗎?謝謝! – jakubka

相關問題