2013-06-18 22 views
6

xmlを処理するためにdictクラスを作成しようとしていますが、固まってしまいました。もし誰かがこの主題を導くことができれば素晴らしいだろう。xmlをpython dictに変換する

これまでに開発されたコード:

class XMLResponse(dict): 
    def __init__(self, xml): 
     self.result = True 
     self.message = '' 
     pass 

    def __setattr__(self, name, val): 
     self[name] = val 

    def __getattr__(self, name): 
     if name in self: 
      return self[name] 
     return None 

message="<?xml version="1.0"?><note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Don't forget me this weekend!</body></note>" 
XMLResponse(message) 
+0

を役に立てば幸いこの質問は以前に回答されているようです: http://stackoverflow.com/questions/2148119/how-to-convert-an-xml-string-to-a-dictionary-in-python – robjohncox

+1

希望する出力は何ですか? – alecxe

+0

@Josh私はあなたのアイデアの友人を理解していません – funktasmas

答えて

18

あなたはxmltodictモジュールを利用することができます:

import xmltodict 

message = """<?xml version="1.0"?><note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Don't forget me this weekend!</body></note>""" 
print xmltodict.parse(message)['note'] 

OrderedDictを生成する:

OrderedDict([(u'to', u'Tove'), (u'from', u'Jani'), (u'heading', u'Reminder'), (u'body', u"Don't forget me this weekend!")]) 

注文が問題でない場合は、dictに変換することができます:

枚の
print dict(xmltodict.parse(message)['note']) 

プリント:

{u'body': u"Don't forget me this weekend!", u'to': u'Tove', u'from': u'Jani', u'heading': u'Reminder'} 
+0

助けてくれてありがとう、 しかし、私はまだそれが追加モジュールなしでどのように実行されたかと思っています。とにかく試してみます。 – funktasmas

+2

@funktasmas:追加のモジュールなしでそれを行う方法を見たいなら、なぜ 'xmltodict'のソースを見てみませんか?これは数百行の清潔でよくコメントされたPythonコードです。そして、それは確かに、誰かが答えを得るために出てくるどんな速く&汚れたハックよりも良くなるだろう。 – abarnert

+0

@abarnertはモジュールをどのように開発しているのか見ていましたが、これは良い方法です。 – funktasmas

5

あなたは

https://github.com/martinblech/xmltodict

をチェックアウトする必要があり、私はそれが私が見たのdictへのXMLのための最高の標準ハンドラの1つだと思います。私はあなたのxmlとdictのを警告する必要がありますしかし

は絶対に互換性のあるデータ構造ではありません

+0

あなたの答えに感謝します。私はまた、完全に互換性のある構造ではないと思うし、過去と同じくらい速い解決策はないと思う。 – funktasmas

+0

@funktasmas:単純なケースの唯一の大きな問題は、XMLノードがサブノードと同様に属性を持つことができ、その表現方法を決定する必要があることです。 'xmltodict'はその名前に接頭辞' @ 'が付いたノードとしての属性を表しますが、それは問題を解決する一つの方法ですが、 '__getitem__'を持つノードや' __getattr__'のattrsを扱うこともできます。 – abarnert

0

あなたはlxml libraryを使用することができます。 objectify.fromstringを使用して文字列をxmlオブジェクトに変換し、オブジェクトのdirメソッドをルックアップします。例:辞書にXMLオブジェクトを変換

from lxml import objectify 

xml_string = """<?xml version="1.0" encoding="UTF-8"?><NewOrderResp><IndustryType></IndustryType><MessageType>R</MessageType><MerchantID>700000005894</MerchantID><TerminalID>0031</TerminalID><CardBrand>AMEX</CardBrand><AccountNum>3456732800000010</AccountNum><OrderID>TESTORDER1</OrderID><TxRefNum>55A69B278025130CD36B3A95435AA84DC45363</TxRefNum><TxRefIdx>10</TxRefIdx><ProcStatus>0</ProcStatus><ApprovalStatus>1</ApprovalStatus><RespCode></RespCode><AVSRespCode></AVSRespCode><CVV2RespCode></CVV2RespCode><AuthCode></AuthCode><RecurringAdviceCd></RecurringAdviceCd><CAVVRespCode></CAVVRespCode><StatusMsg></StatusMsg><RespMsg></RespMsg><HostRespCode></HostRespCode><HostAVSRespCode></HostAVSRespCode><HostCVV2RespCode></HostCVV2RespCode><CustomerRefNum>A51C5B2B1811E5991208</CustomerRefNum><CustomerName>BOB STEVEN</CustomerName><ProfileProcStatus>0</ProfileProcStatus><CustomerProfileMessage>Profile Created</CustomerProfileMessage><RespTime>13055</RespTime><PartialAuthOccurred></PartialAuthOccurred><RequestedAmount></RequestedAmount><RedeemedAmount></RedeemedAmount><RemainingBalance></RemainingBalance><CountryFraudFilterStatus></CountryFraudFilterStatus><IsoCountryCode></IsoCountryCode></NewOrderResp>""" 

xml_object = objectify.fromstring(xml_string) 

print xml_object.__dict__ 

は辞書を返します:

{'RemainingBalance': u'', 'AVSRespCode': u'', 'RequestedAmount': u'', 'AccountNum': 3456732800000010, 'IsoCountryCode': u'', 'HostCVV2RespCode': u'', 'TerminalID': 31, 'CVV2RespCode': u'', 'RespMsg': u'', 'CardBrand': 'AMEX', 'MerchantID': 700000005894, 'RespCode': u'', 'ProfileProcStatus': 0, 'CustomerName': 'BOB STEVEN', 'PartialAuthOccurred': u'', 'MessageType': 'R', 'ProcStatus': 0, 'TxRefIdx': 10, 'RecurringAdviceCd': u'', 'IndustryType': u'', 'OrderID': 'TESTORDER1', 'StatusMsg': u'', 'ApprovalStatus': 1, 'RedeemedAmount': u'', 'CountryFraudFilterStatus': u'', 'TxRefNum': '55A69B278025130CD36B3A95435AA84DC45363', 'CustomerRefNum': 'A51C5B2B1811E5991208', 'CustomerProfileMessage': 'Profile Created', 'AuthCode': u'', 'RespTime': 13055, 'HostAVSRespCode': u'', 'CAVVRespCode': u'', 'HostRespCode': u''} 

私が使用したXML文字列ペイメンテックの支払いからの応答は、単に現実世界の例を示すために、ゲートウェイです。

上記の例は再帰的なものではないことに注意してください.dicts内にdictsがある場合、再帰を行う必要があります。親キー/要素を保持するバリアント相続人

from lxml import objectify 

def xml_to_dict_recursion(xml_object): 
    dict_object = xml_object.__dict__ 
    if not dict_object: 
     return xml_object 
    for key, value in dict_object.items(): 
     dict_object[key] = xml_to_dict_recursion(value) 
    return dict_object 

def xml_to_dict(xml_str): 
    return xml_to_dict_recursion(objectify.fromstring(xml_str)) 

xml_string = """<?xml version="1.0" encoding="UTF-8"?><Response><NewOrderResp> 
<IndustryType>Test</IndustryType><SomeData><SomeNestedData1>1234</SomeNestedData1> 
<SomeNestedData2>3455</SomeNestedData2></SomeData></NewOrderResp></Response>""" 

print xml_to_dict(xml_string) 

def xml_to_dict(xml_str): 
    """ Convert xml to dict, using lxml v3.4.2 xml processing library, see http://lxml.de/ """ 
    def xml_to_dict_recursion(xml_object): 
     dict_object = xml_object.__dict__ 
     if not dict_object: # if empty dict returned 
      return xml_object 
     for key, value in dict_object.items(): 
      dict_object[key] = xml_to_dict_recursion(value) 
     return dict_object 
    xml_obj = objectify.fromstring(xml_str) 
    return {xml_obj.tag: xml_to_dict_recursion(xml_obj)} 

そして、あなたが唯一のサブツリーを返し、辞書に変換したい場合、私はあなたが使用できることを書いた再帰関数を参照してください。 、あなたは)Element.findを(使用することができます。

xml_obj.find('.//') # lxml.objectify.ObjectifiedElement instance 

はこれを達成するための多くのオプションがありますが、あなたはすでにlxmlのを使用している場合はこの1つは素晴らしいです。この例では、lxml-3.4.2が使用されました。

3

あなたは今これで良い答えを得ていると思いますが、明らかにそうではありませんでした。 stackoverflowの上の同様の質問のダースの半分を確認した後、ここに私の仕事です:

from lxml import etree 
# arrow is an awesome lib for dealing with dates in python 
import arrow 


# converts an etree to dict, useful to convert xml to dict 
def etree2dict(tree): 
    root, contents = recursive_dict(tree) 
    return {root: contents} 


def recursive_dict(element): 
    if element.attrib and 'type' in element.attrib and element.attrib['type'] == "array": 
     return element.tag, [(dict(map(recursive_dict, child)) or getElementValue(child)) for child in element] 
    else: 
     return element.tag, dict(map(recursive_dict, element)) or getElementValue(element) 


def getElementValue(element): 
    if element.text: 
     if element.attrib and 'type' in element.attrib: 
      attr_type = element.attrib.get('type') 
      if attr_type == 'integer': 
       return int(element.text.strip()) 
      if attr_type == 'float': 
       return float(element.text.strip()) 
      if attr_type == 'boolean': 
       return element.text.lower().strip() == 'true' 
      if attr_type == 'datetime': 
       return arrow.get(element.text.strip()).timestamp 
     else: 
      return element.text 
    elif element.attrib: 
     if 'nil' in element.attrib: 
      return None 
     else: 
      return element.attrib 
    else: 
     return None 

、これはあなたがそれを使用する方法である:

from lxml import etree 

message="""<?xml version="1.0"?><note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Don't forget me this weekend!</body></note>"'' 
tree = etree.fromstring(message) 
etree2dict(tree) 

はそれが:-)

関連する問題