How to preserve indenting in key-value when dumping yaml

五迷三道 提交于 2020-01-15 08:12:58

问题


How to preserve indenting in key-value when dumping yaml ? I am using ruamel yaml

Code:

in_str='''Pets:
    Cat:
       Tom
    Mouse:
       Jerry
    Dog:
       Scooby
       '''


import ruamel.yaml, sys
results = ruamel.yaml.load(in_str, ruamel.yaml.RoundTripLoader, preserve_quotes=True)
results['Pets']['Bird']='Tweety'
ruamel.yaml.dump(results, sys.stdout, ruamel.yaml.RoundTripDumper, default_flow_style=True,indent=2, block_seq_indent=2)

Output :

Pets:
  Cat: Tom
  Mouse: Jerry
  Dog: Scooby
  Bird: Tweety

Expected Output:

Pets:
    Cat:
       Tom
    Mouse:
       Jerry
    Dog:
       Scooby
    Bird:
       Tweety

回答1:


In order to achieve this you'll have to hook into the Emitter and have it insert a newline and appropriate indentation when processing a mapping value. This can be done with the old style API that you use, but is better done with the new ruamel.yaml API, which gives you e.g. the possibility to indent sequences and mappings with different values:

import sys
import ruamel.yaml
from ruamel.yaml.emitter import Emitter

class MyEmitter(Emitter):
    def expect_block_mapping_simple_value(self):
        # type: () -> None
        if getattr(self.event, 'style', None) != '?':
            # prefix = u''
            if self.indent == 0 and self.top_level_colon_align is not None:
                # write non-prefixed colon
                c = u' ' * (self.top_level_colon_align - self.column) + self.colon
            else:
                c = self.prefixed_colon
            self.write_indicator(c, False)
            # the next four lines force a line break and proper indent of the value
            self.write_line_break()
            self.indent += self.best_map_indent
            self.write_indent()
            self.indent -= self.best_map_indent
        self.states.append(self.expect_block_mapping_key)
        self.expect_node(mapping=True)


in_str='''\
Pets:
    Cat:
       Tom
    Mouse:
       - Jerry
       - 'Mickey'
    Dog:
       Scooby
       '''

yaml = ruamel.yaml.YAML()
yaml.Emitter = MyEmitter
yaml.indent(mapping=4, sequence=2, offset=0)
yaml.preserve_quotes = True
results = yaml.load(in_str)
results['Pets']['Bird']='Tweety'
yaml.dump(results, sys.stdout)

this gives:

Pets:
    Cat:
        Tom
    Mouse:
        - Jerry
        - 'Mickey'
    Dog:
        Scooby
    Bird:
        Tweety

Things to note:

  • You only have to handle simple scalar values (as opposed to mappings/sequences, which are already "pushed" to the next line in block sequence "mode")
  • The expect_block_mapping_simple_value is copied from the source and a few lines added. There is currently no "hook" to do this without duplicating some code.
  • You can play with the sequence and offset values for yaml.indent() if you have sequences and need different indentation for that.
  • All of this assumes consistent indenting, individual indentation is not preserved (i.e. if some values are indented with more or less than the four positions, they'll end up with 4 positions).


来源:https://stackoverflow.com/questions/48029461/how-to-preserve-indenting-in-key-value-when-dumping-yaml

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!