2010-11-06 62 views
1

我有以下功能,能源部的映射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> 

谢谢:)

+3

使用词典将只允许与主要a或b元素你怎么想的是 - 即最佳展示一下您所需的输出 – Mark 2010-11-06 11:10:41

+0

已经改写问题,包括需要输出 - 感谢马克 – significance 2010-11-06 11:28:24

回答

5

好,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) 

这使得在字典作为defaultdict标签输入;如果由于某种原因需要正常字典,请使用d[el.tag] = dict(child_dicts)。请注意,和以前一样,如果标签同时包含文本和子项,则文本将不会出现在字典中。你可能想考虑一下你的字典的不同布局来应对这种情况。

编辑:会产生在你的改写问题的输出不会在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标签的文本数据串,你必须明确地把它们变成整数不知)

+0

对不起托马斯,这是对我原来的问题非常正确的答案,但不幸的是我第一次不够具体。我已经重述了这个问题 - 希望你能提供帮助。对不起,麻烦... – significance 2010-11-06 13:21:08

+0

完美 - 非常感谢您回复我两次! – significance 2010-11-06 16:17:46

+0

托马斯 - 抱歉再次提出这个问题,但我在实现collections.OrderedDict而不是collections.defaultdict时遇到了问题 - 希望你能帮上忙!非常感谢 :) – significance 2010-11-08 15:02:58

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}})