Принятый ответ обрабатывает только скаляры. Мне также нужны типы отображения. Я хотел универсальное решение. Я думаю, что я, возможно, перепроектировал это. Я чувствую, что это может быть проще, и дальнейшее упрощение приветствуется.
Итак, если у вас есть Yaml, это выглядит примерно так:
Name: !Foo bar
Alt: !Bar foo
other: !Join
- thing
- other thing
textblock: !Mangle |
This is a block
of text that
spans lines
Попробуйте этот более длинный фрагмент кода:
import sys
import yaml
import pprint
yaml_str = """\
Name: !Foo bar
Alt: !Bar foo
other: !Join
- thing
- other thing
textblock: !Mangle |
This is a block
of text that
spans lines
"""
class SafeUnknownConstructor(yaml.constructor.SafeConstructor):
def __init__(self):
yaml.constructor.SafeConstructor.__init__(self)
def construct_undefined(self, node):
data = getattr(self, 'construct_' + node.id)(node)
datatype = type(data)
wraptype = type('TagWrap_'+datatype.__name__, (datatype,), {})
wrapdata = wraptype(data)
wrapdata.tag = lambda: None
wrapdata.datatype = lambda: None
setattr(wrapdata, "wrapTag", node.tag)
setattr(wrapdata, "wrapType", datatype)
return wrapdata
class SafeUnknownLoader(SafeUnknownConstructor, yaml.loader.SafeLoader):
def __init__(self, stream):
SafeUnknownConstructor.__init__(self)
yaml.loader.SafeLoader.__init__(self, stream)
class SafeUnknownRepresenter(yaml.representer.SafeRepresenter):
def represent_data(self, wrapdata):
tag = False
if type(wrapdata).__name__.startswith('TagWrap_'):
datatype = getattr(wrapdata, "wrapType")
tag = getattr(wrapdata, "wrapTag")
data = datatype(wrapdata)
else:
data = wrapdata
node = super(SafeUnknownRepresenter, self).represent_data(data)
if tag:
node.tag = tag
return node
class SafeUnknownDumper(SafeUnknownRepresenter, yaml.dumper.SafeDumper):
def __init__(self, stream,
default_style=None, default_flow_style=False,
canonical=None, indent=None, width=None,
allow_unicode=None, line_break=None,
encoding=None, explicit_start=None, explicit_end=None,
version=None, tags=None, sort_keys=True):
SafeUnknownRepresenter.__init__(self, default_style=default_style,
default_flow_style=default_flow_style, sort_keys=sort_keys)
yaml.dumper.SafeDumper.__init__(self, stream,
default_style=default_style,
default_flow_style=default_flow_style,
canonical=canonical,
indent=indent,
width=width,
allow_unicode=allow_unicode,
line_break=line_break,
encoding=encoding,
explicit_start=explicit_start,
explicit_end=explicit_end,
version=version,
tags=tags,
sort_keys=sort_keys)
MySafeLoader = SafeUnknownLoader
yaml.constructor.SafeConstructor.add_constructor(None, SafeUnknownConstructor.construct_undefined)
data = yaml.load(yaml_str, MySafeLoader)
pprint.pprint(data)
yaml.dump_all([data], sys.stdout, Dumper=SafeUnknownDumper, default_flow_style=False, allow_unicode=True)
Что выводит:
{'Alt': u'foo',
'Name': u'bar',
'other': ['thing', 'other thing'],
'textblock': u'This is a block\nof text that \nspans lines\n'}
Alt: !Bar 'foo'
Name: !Foo 'bar'
other: !Join
- thing
- other thing
textblock: !Mangle "This is a block\nof text that \nspans lines\n"
Примечание. Если добавленный код обновляет данные и не проверяет оболочку, он может вернуть элементы к развернутому типу и потерять тег.
person
Frobbit
schedule
21.03.2020
yaml.load()
небезопасно, поскольку кто-то может выполнить произвольный код, если у него есть контроль над файлом YAML, а PyYAML не предупреждает об опасностях. - person Anthon   schedule 03.05.2017