事实证明,我能够将dnozay answer 修改为“Any yaml libraries in Python that support dumping of long strings as block literals or folded blocks?”问题。
结果证明它比flyx answer 快一点,但您需要一些额外的技巧(借用drbild/json2yaml 的修改)来保持键的顺序。
主要是使用Representer.add_representer:
class maybe_literal_str(str): pass
class maybe_literal_unicode(unicode): pass
def change_maybe_style(representer):
def new_maybe_representer(dumper, data):
scalar = representer(dumper, data)
if isinstance(data, basestring) and "\n" in data:
scalar.style = '|'
else:
scalar.style = None
return scalar
return new_maybe_representer
from yaml.representer import SafeRepresenter
# represent_str does handle some corner cases, so use that
# instead of calling represent_scalar directly
represent_maybe_literal_str = change_maybe_style(SafeRepresenter.represent_str)
represent_maybe_literal_unicode = change_maybe_style(SafeRepresenter.represent_unicode)
# I needed to use it in yaml.safe_dump() with older PyYAML,
# hence explicit Dumper=yaml=SafeDumper
yaml.add_representer(maybe_literal_str, represent_maybe_literal_str,
Dumper=yaml.SafeDumper)
yaml.add_representer(maybe_literal_unicode, represent_maybe_literal_unicode,
Dumper=yaml.SafeDumper)
为了让它工作,我必须用这两个类之一来包装字符串:
def wrap_strings(arg):
"""Wrap {str,unicode} arguments in maybe_literal_{str,unicode}"""
if isinstance(arg, str):
return maybe_literal_str(arg)
elif isinstance(arg, unicode):
return maybe_literal_unicode(arg)
else:
return arg
我用这个hacky函数来修改结构
def transform(obj, leaf_callback):
try:
# is it dict or something like it?
enum = obj.iteritems()
except AttributeError:
# if not dict-like, it is list-like object
enum = enumerate(obj)
for k, v in enum:
# is value 'v' collection or scalar (leaf value)?
if isinstance(v, (dict, list)):
transform(v, leaf_callback)
else:
newval = leaf_callback(v)
if newval is not None:
obj[k] = newval
从 JSON 到 YAML 的转换是通过以下方式完成的:
def convert_dom(json_file, yaml_file):
loaded_json = json.load(json_file)
transform(loaded_json, wrap_strings)
yaml.safe_dump(loaded_json, yaml_file,
explicit_start=True, # start with "---\n"
default_flow_style=False)
with open('in.json', 'r') as json_file:
with open('out.yaml', 'w') as yaml_file:
convert_events(json_file, yaml_file)