问题
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
andoffset
values foryaml.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