2016-12-28 71 views
4

使用ruamel.yaml我試圖讓在特定式樣下的YAML,更具體地一個,其中單一行的字符串在同一行:和多行字符串開始使用摺疊標量樣式(|/|-)和線受限於一定數量的字符(文字包裝)。將YAML多行值轉換爲摺疊塊標量樣式?

我嘗試到目前爲止很大程度上由similar function called walk_tree in the sources影響:

#!/usr/bin/env python 

import ruamel.yaml 

from ruamel.yaml.scalarstring import ScalarString, PreservedScalarString 

def walk_tree(base): 
    from ruamel.yaml.compat import string_types 

    if isinstance(base, dict): 
     for k in base: 
      v = base[k] 
      if isinstance(v, string_types): 
       v = v.replace('\r\n', '\n').replace('\r', '\n').strip() 
       base[k] = ScalarString(v) if '\n' in v else v 
      else: 
       walk_tree(v) 
    elif isinstance(base, list): 
     for idx, elem in enumerate(base): 
      if isinstance(elem, string_types) and '\n' in elem: 
       print(elem) # @Anthon: this print is in the original code as well 
       base[idx] = preserve_literal(elem) 
      else: 
       walk_tree(elem) 

with open("input.yaml", "r") as fi: 
    inp = fi.read() 

loader=ruamel.yaml.RoundTripLoader 
data = ruamel.yaml.load(inp, loader) 

walk_tree(data) 

dumper = ruamel.yaml.RoundTripDumper 

with open("output.yaml", "w") as fo: 
    ruamel.yaml.dump(data, fo, Dumper=dumper, allow_unicode=True) 

但後來我得到一個異常:ruamel.yaml.representer.RepresenterError: cannot represent an object: …。如果我將ScalarString替換爲PreservedScalarString,與原始walk_tree代碼中的情況一樣,我也不例外,但是我再次得到了不是我想要的文字塊。

那麼我的代碼如何修復以便它能夠工作?

+0

默認以上增加72至'print'呼叫將在0.13.8消失了,謝謝指出。 – Anthon

+0

如果我的回答不能滿足您的需求,請將樣品輸入(並輸出,如果不同)YAML文件,請將其編輯到您的問題中。如果你這樣做,你不應該放入* EDIT *。留下一個簡短的評論,這將觸發通知。 – Anthon

回答

2

ScalarString這個類是PreservedScalarString的基類,因此您找不到代表。你應該只是將這個字符串保存爲Python字符串,因爲它適當處理特殊字符(引用需要引用的字符串以符合YAML規範)。

假設你有一個像這樣輸入:

- 1 
- abc: | 
    this is a short string scalar with a newline 
    in it 
- "there are also a multiline\nsequence element\nin this file\nand it is longer" 

你可能想這樣做:

import ruamel.yaml 
from ruamel.yaml.scalarstring import PreservedScalarString, preserve_literal 


def walk_tree(base): 
    from ruamel.yaml.compat import string_types 

    def test_wrap(v): 
     v = v.replace('\r\n', '\n').replace('\r', '\n').strip() 
     return v if len(v) < 72 else preserve_literal(v) 

    if isinstance(base, dict): 
     for k in base: 
      v = base[k] 
      if isinstance(v, string_types) and '\n' in v: 
       base[k] = test_wrap(v) 
      else: 
       walk_tree(v) 
    elif isinstance(base, list): 
     for idx, elem in enumerate(base): 
      if isinstance(elem, string_types) and '\n' in elem: 
       base[idx] = test_wrap(elem) 
      else: 
       walk_tree(elem) 

with open("input.yaml", "r") as fi: 
    data = ruamel.yaml.round_trip_load(fi) 

walk_tree(data) 

with open("output.yaml", "w") as fo: 
    ruamel.yaml.round_trip_dump(data, fo) 

得到輸出:

- 1 
- abc: "this is a short string scalar with a newline\nin it" 
- |- 
    there are also a multiline 
    sequence element 
    in this file 
    and it is longer 

一些注意事項:

  • 您可能沒有序列元素,其中字符串,因爲您沒有導入preserve_literal,雖然它仍然在複製的代碼中使用。
  • 我將「包裝」代碼分解爲test_wrap,由值和元素換行使用,其最大行長度設置爲72個字符。
  • data[1]['abc']加載爲PreservedScalarString。如果要保留現有的文字樣式字符串標量,則應在測試string_types類型之前對其進行測試。
  • 我使用了速記功能round_trip_load()round_trip_dump()(後者自動爲allow_unicode=True)。
  • 您可能必須在width參數設置爲round_trip_dump()成類似1000,以避免自動換行,如果您在本例中的80