2016-11-14 38 views
1

我有一個YAML文件,我想解析。如何在PyYAML分析器中掛鉤過濾器?

出於多種原因,我想禁止在錨使用點.的只是_取代它,在解析階段。

簡單地說,我想從這個去:

foo: 
    bar.baz: 
     - egg 
     - spam 

到:

foo: 
    bar_baz: 
     - egg 
     - spam 

據我所知,這種轉變可能對得到的Python字典進行,但它不是正確的位置:解析器應該拋出一個錯誤,或者它應該替換違規值。

我已經嘗試子類Loader爲了做這種轉換,但沒有重寫的函數似乎有任何影響。

+0

你們認爲「節點名稱」的round_trip_load/dump? YAML 1.2有節點,但根據規範沒有名稱(對於較早的YAML 1.1也是如此,PyYAML可以處理該節點)。你是否將標籤稱爲「節點名稱」或錨?或者你是否在談論將密鑰映射爲節點名稱?如果你給了一個小例子的YAML文件(最好用一個手工「轉換」的版本)。所有這些(錨點,標籤,鍵)都可以隨時更改,但需要不同的編程。 – Anthon

+0

已更新。問題很簡單,我只是希望鉤子也會。 :) – JohnW

+0

這是映射節點中鍵值對的關鍵。 'Loader'需要另外一個'Constructor',這並不是微不足道的。 – Anthon

回答

0

沒有一種簡單的機制可以通過每個映射關鍵字通過的某個鉤子的形式替換關鍵字(無論如何,您可能希望擁有比擁有關鍵字更多的上下文)。 有關於如何解決此不同的方法:

  • 你可以做一個新的Loader,這將有自己的Constructor子,做的映射按鍵的轉變。這是IMO正確的解決方案,因爲它不會影響其他YAML的加載。然而,它也是一個比較棘手的問題,你可以爲你正在使用的Loader添加一個新的映射構造函數,從而覆蓋現有的構造函數。這會影響未來所有YAML文件的加載,如果你沒有做任何特殊的事情。
  • 你可以包裝現有的映射構造函數,加載你的YAML並移回原來的東西。這然後不影響進一步的YAML文件的加載。

這些後者可以這樣做:

import sys 
import ruamel.yaml 

yaml_str = """\ 
foo: 
    bar.baz: 
     - egg 
     - spam 
""" 


def alt_construct_mapping(self, *args, **kw): 
    """replace keys with dot""" 
    m = self.org_construct_mapping(*args, **kw) 
    for k in m: 
     if '.' in k: 
      m[k.replace('.', '_')] = m.pop(k) 
    return m 

# backup up the constructor 
ruamel.yaml.constructor.BaseConstructor.org_construct_mapping = \ 
    ruamel.yaml.constructor.BaseConstructor.construct_mapping 

# replace the constructor 
ruamel.yaml.constructor.BaseConstructor.construct_mapping = alt_construct_mapping 


data = ruamel.yaml.safe_load(yaml_str) 
ruamel.yaml.round_trip_dump(data, sys.stdout) 

# put original constructor back 
ruamel.yaml.constructor.BaseConstructor.construct_mapping = \ 
    ruamel.yaml.constructor.BaseConstructor.org_construct_mapping 

這給:

foo: 
    bar_baz: 
    - egg 
    - spam 

這是使用ruamel.yaml,PyYAML的增強版本,其中我是筆者做。對於PyYAML這應該工作以及只要你的YAML沒有任何YAML 1.2版本構建,更換ruamel.yamlyamlsafe_load/dump