2010-11-06 30 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}})