【问题标题】:A pyyaml parser to list-ify values for the same key用于列出相同键的值的 pyyaml 解析器
【发布时间】:2021-09-22 22:35:33
【问题描述】:

我知道这不是严格有效的 YAML,但我想知道如何修改我的 pyyaml 解析器以将与重复键关联的值分组到一个列表中。

所以,我有以下内容:

import yaml
from io import StringIO

data = """
NAME: Best Test
TEST: True

More: Yes

NO_LEADING_ZEROS: 0713

ENTITY:
    Name: Great
    Value: 10

ENTITY:
    Name: Even better
    Value: 11

"""

with StringIO(data) as f:
    parsed = yaml.load(f.read(), Loader=yaml.BaseLoader)
print(parsed)

assert(isinstance(parsed.get("ENTITY"), list))

我得到以下信息:

{'NAME': 'Best Test', 
'TEST': 'True', 
'ENTITY': {'Name': 'Even better', 'Value': '11'}, 
'More': 'Yes', 
'NO_LEADING_ZEROS': '0713'}

假设我不能更改“yaml”,只能更改我的解析器,我会更改什么来获取以下字典?

{'NAME': 'Best Test', 
'TEST': 'True', 
'ENTITY': [
  {'Name': 'Great', 'Value': '10'}
  {'Name': 'Even better', 'Value': '11'}], 
'More': 'Yes', 
'NO_LEADING_ZEROS': '0713'}

我看到这个答案看起来很相似Getting duplicate keys in YAML using Python

但是该解决方案不适用于我的用例,因为它只是将每个字段都放入一个列表中,然后返回:

{'NAME': ['Best Test'], 
 'TEST': [True], 
  'ENTITY': [defaultdict(<class 'list'>, 
     {'Name': ['Great'], 'Value': [10]}), 
             defaultdict(<class 'list'>, 
     {'Name': ['Even better'], 'Value': [11]})], 
'More': [True], 
'NO_LEADING_ZEROS': [459]})

【问题讨论】:

    标签: python parsing yaml pyyaml


    【解决方案1】:

    您链接的问题提供了一个解决方案,只需稍作修改即可完成您想要的操作:

    import yaml
    
    def parse_preserving_duplicates(src):
        # We deliberately define a fresh class inside the function,
        # because add_constructor is a class method and we don't want to
        # mutate pyyaml classes.
        class PreserveDuplicatesLoader(yaml.loader.Loader):
            pass
    
        def map_constructor(loader, node, deep=False):
            """Walk the mapping, recording any duplicate keys.
    
            """
            mapping = {}
            for key_node, value_node in node.value:
                key = loader.construct_object(key_node, deep=deep)
                value = loader.construct_object(value_node, deep=deep)
    
                if key not in mapping:
                  mapping[key] = []
    
                mapping[key].append(value)
    
            for k,v in mapping.items():
               if len(v) == 1:
                 mapping[k] = v[0]
            return mapping
    
        PreserveDuplicatesLoader.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, map_constructor)
        return yaml.load(src, PreserveDuplicatesLoader)
    

    我删除了defaultdict,因为虽然它对加载很有用,但您可能不希望所有内容都成为默认字典。在构造mapping 之后,我添加了代码,如果键只有一个值,则删除该值周围的列表。这只会为您提供实际多次出现的键的列表。

    【讨论】:

      猜你喜欢
      • 2014-07-19
      • 1970-01-01
      • 2020-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多