【问题标题】:how do i map to a dictionary rather than a list?我如何映射到字典而不是列表?
【发布时间】:2010-11-06 10:49:34
【问题描述】:

我有以下函数,它完成了将 lxml 对象映射到字典的基本工作......

from lxml import etree 

tree = etree.parse('file.xml')
root = tree.getroot()

def xml_to_dict(el):
    d={}
    if el.text:
        print '***write tag as string'
        d[el.tag] = el.text
    else:
        d[el.tag] = {}
    children = el.getchildren()
    if children:
        d[el.tag] = map(xml_to_dict, children)
    return d

    v = xml_to_dict(root)

此刻它给了我....

>>>print v
{'root': [{'a': '1'}, {'a': [{'b': '2'}, {'b': '2'}]}, {'aa': '1a'}]}

但我想....

>>>print v
{'root': {'a': ['1', {'b': [2, 2]}], 'aa': '1a'}}

如何重写函数 xml_to_dict(el) 以获得所需的输出?

为了清楚起见,这是我正在解析的 xml。

<root>
    <a>1</a>
    <a>
        <b>2</b>
        <b>2</b>
    </a>
    <aa>1a</aa>
</root>

谢谢:)

【问题讨论】:

  • 使用字典将只允许在带有键 a 或 b 的元素上,您希望如何 - 即最好显示您需要的输出是什么
  • 已经改写了问题以包含所需的输出 - 谢谢马克

标签: python xml list dictionary lxml


【解决方案1】:

好吧,map() 总是会返回一个列表,所以简单的答案是“不要使用 map()”。相反,通过循环 children 并将 xml_to_dict(child) 的结果分配给您要使用的字典键,构建一个像您现在这样的字典。看起来你想使用标签作为键,并且值是带有该标签的项目列表,所以它会变成这样:

import collections
from lxml import etree

tree = etree.parse('file.xml')
root = tree.getroot()

def xml_to_dict(el):
    d={}
    if el.text:
        print '***write tag as string'
        d[el.tag] = el.text
    child_dicts = collections.defaultdict(list)
    for child in el.getchildren():
        child_dicts[child.tag].append(xml_to_dict(child))
    if child_dicts:
        d[el.tag] = child_dicts
    return d

xml_to_dict(root)

这会将字典中的标签条目保留为默认字典;如果您出于某种原因想要一个普通的字典,请使用d[el.tag] = dict(child_dicts)。请注意,和以前一样,如果标签同时具有文本和子项,则文本不会出现在字典中。您可能需要为您的 dict 考虑一种不同的布局来应对这种情况。

编辑:

在你改写的问题中产生输出的代码不会在xml_to_dict 中递归——因为你只需要一个外部元素的字典,而不是所有子标签。所以,你会使用类似的东西:

import collections
from lxml import etree

tree = etree.parse('file.xml')
root = tree.getroot()

def xml_to_item(el):
    if el.text:
        print '***write tag as string'
        item = el.text
    child_dicts = collections.defaultdict(list)
    for child in el.getchildren():
        child_dicts[child.tag].append(xml_to_item(child))
    return dict(child_dicts) or item

def xml_to_dict(el):
    return {el.tag: xml_to_item(el)}

print xml_to_dict(root)

这仍然不能很好地处理带有文本和子项的标签,它会将collections.defaultdict(list) 转换为普通字典,因此输出(几乎)如您所料:

***write tag as string
***write tag as string
***write tag as string
***write tag as string
***write tag as string
***write tag as string
{'root': {'a': ['1', {'b': ['2', '2']}], 'aa': ['1a']}}

(如果您真的想要整数而不是 b 标记中的文本数据的字符串,则必须以某种方式显式将它们转换为整数。)

【讨论】:

  • 对不起托马斯,这几乎是对我最初问题的正确答案,但不幸的是我第一次不够具体。我已经改写了这个问题-希望您能提供帮助。抱歉给您添麻烦了……
  • thomas - 很抱歉再次提出这个问题,但我在实现 collections.OrderedDict 而不是 collections.defaultdict 时遇到了麻烦 - 希望你能提供帮助!非常感谢:)
【解决方案2】:

更简单:

from lxml import etree    
def recursive_dict(element):
    return element.tag, dict(map(recursive_dict, element)) or element.text

使用它:

   >> tree = etree.parse(file_name)
   >> recursive_dict(tree.getroot())
   ('root', {'tag1': text, 'tag2': subtag21: {tag211: text}})

编辑:问题示例的输出:

('root', {'a': {'b': '2'}, 'aa': '1a'})

etree 似乎跳过了重复的元素。

【讨论】:

    猜你喜欢
    • 2010-12-31
    • 1970-01-01
    • 1970-01-01
    • 2018-09-21
    • 1970-01-01
    • 1970-01-01
    • 2020-10-30
    • 2021-07-28
    相关资源
    最近更新 更多