pyyaml ​​анализирует данные с тегом - PullRequest
0 голосов
/ 08 декабря 2018

У меня есть данные yaml, такие как входные данные ниже, и мне нужно вывести в виде пар ключ-значение

Ввод

a="""
--- !ruby/hash:ActiveSupport::HashWithIndifferentAccess
code:
- '716'
- '718'
id:
- 488
- 499
"""

Требуется вывод

{'code': ['716', '718'], 'id': [488, 499]}

Конструктор по умолчанию былдавая мне ошибку.Я попытался добавить новый конструктор, и теперь он не дает мне ошибку, но я не могу получить пары ключ-значение.К вашему сведению, если я уберу строку !ruby/hash:ActiveSupport::HashWithIndifferentAccess из моего yaml, то это даст мне желаемый результат.

def new_constructor(loader, tag_suffix, node):

     if type(node.value)=='list':
         val=''.join(node.value)
     else:
         val=node.value
     val=node.value
     ret_val="""
     {0}
     """.format(val)
     return ret_val

yaml.add_multi_constructor('', new_constructor)
yaml.load(a)

output

"\n     [(ScalarNode(tag=u'tag:yaml.org,2002:str', value=u'code'), SequenceNode(tag=u'tag:yaml.org,2002:seq', value=[ScalarNode(tag=u'tag:yaml.org,2002:str', value=u'716'), ScalarNode(tag=u'tag:yaml.org,2002:str', value=u'718')])), (ScalarNode(tag=u'tag:yaml.org,2002:str', value=u'id'), SequenceNode(tag=u'tag:yaml.org,2002:seq', value=[ScalarNode(tag=u'tag:yaml.org,2002:int', value=u'488'), ScalarNode(tag=u'tag:yaml.org,2002:int', value=u'499')]))]\n     "

Пожалуйста, предложите.

Ответы [ 2 ]

0 голосов
/ 08 декабря 2018

Я настоятельно рекомендую следовать ответу @Andrew F, но в случае, если вам интересно, почему ваш код не получил правильный результат, потому что вы неправильно обрабатываете узел под тегом при обработке тегов.

Хотя значение узла является списком (кортежей с парами ключ-значение), вы должны проверить тип самого узла (используя isinstance), а затем передать его в «обычную» процедуру обработки отображения в качестве тега.находится на отображении:

import yaml
from yaml.loader import SafeLoader

a = """\
--- !ruby/hash:ActiveSupport::HashWithIndifferentAccess
code:
- '716'
- '718'
id:
- 488
- 499
"""

def new_constructor(loader, tag_suffix, node):
    if isinstance(node, yaml.nodes.MappingNode):
        return loader.construct_mapping(node, deep=True)
    raise NotImplementedError

yaml.add_multi_constructor('', new_constructor, Loader=SafeLoader)


data = yaml.load(a, Loader=SafeLoader)
print(data)

, что дает:

{'code': ['716', '718'], 'id': [488, 499]}

Вы не должны использовать yaml.load() PyYAML, это задокументировано как потенциально небезопасное и, прежде всего, в этом нет необходимости.Просто добавьте новый конструктор в SafeLoader.

0 голосов
/ 08 декабря 2018

Это не решение с использованием PyYAML, но я рекомендую использовать ruamel.yaml.Если по какой-либо другой причине он поддерживается более активно, чем PyYAML.Цитата из обзора

Многие ошибки, обнаруженные в PyYAML, но которые никогда не были устранены, были исправлены в ruamel.yaml

Чтобы загрузить эту строку,Вы можете сделать

import ruamel.yaml
parser = ruamel.yaml.YAML()

obj = parser.load(a)  # as defined above.
...