11 Stimmen

Konvertiere XML in ein Python-Wörterbuch

Ich versuche, eine dict-Klasse zu erstellen, um ein XML zu verarbeiten, komme aber nicht weiter. Mir gehen wirklich die Ideen aus. Wenn jemand in diesem Bereich helfen könnte, wäre das großartig.

Bisher entwickelter Code:

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="ToveJaniReminderDon't forget me this weekend!"
XMLResponse(message)

21voto

alecxe Punkte 437954

Sie können das xmltodict Modul verwenden:

import xmltodict

message = """ToveJaniReminderVergiss mich nicht dieses Wochenende!"""
print xmltodict.parse(message)['note']

das eine OrderedDict produziert:

OrderedDict([(u'to', u'Tove'), (u'from', u'Jani'), (u'heading', u'Reminder'), (u'body', u"Vergiss mich nicht dieses Wochenende!")])

das in ein dict umgewandelt werden kann, falls die Reihenfolge keine Rolle spielt:

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

Druckt:

{u'body': u"Vergiss mich nicht dieses Wochenende!", u'to': u'Tove', u'from': u'Jani', u'heading': u'Reminder'}

7voto

Fred Punkte 615

Sie würden denken, dass wir inzwischen eine gute Antwort darauf haben würden, aber anscheinend haben wir das nicht. Nachdem ich mir ein halbes Dutzend ähnlicher Fragen auf Stackoverflow angesehen habe, hier ist, was für mich funktioniert hat:

from lxml import etree
# arrow ist eine großartige Bibliothek für den Umgang mit Datumsangaben in Python
import arrow

# wandelt ein etree in ein Wörterbuch um, nützlich um XML in ein Wörterbuch umzuwandeln
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

und so verwenden Sie es:

from lxml import etree

message="""ToveJaniErinnerungVergiss mich dieses Wochenende nicht!"''
tree = etree.fromstring(message)
etree2dict(tree)

Ich hoffe, das hilft :-)

6voto

dusual Punkte 2037

Sie sollten auschecken

https://github.com/martinblech/xmltodict

Ich denke, es ist einer der besten Standard-Handler für XML zu Dict, die ich gesehen habe.

Allerdings sollte ich Sie warnen, XML und Dict sind nicht absolut kompatible Datenstrukturen

3voto

radtek Punkte 30114

Sie können die lxml-Bibliothek verwenden. Konvertieren Sie den String in ein XML-Objekt mit objectify.fromstring und sehen Sie dann die Objekte mit der dir-Methode nach. Zum Beispiel:

from lxml import objectify

xml_string = """R7000000058940031AMEX3456732800000010TESTORDER155A69B278025130CD36B3A95435AA84DC453631001A51C5B2B1811E5991208BOB STEVEN0Profile Created13055"""

xml_object = objectify.fromstring(xml_string)

print xml_object.__dict__

Wenn Sie das XML-Objekt in ein Dictionary konvertieren, erhalten Sie folgendes Dictionary:

{'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''}

Der XML-String, den ich verwendet habe, ist eine Antwort von Paymentech Payments Gateway, nur um ein reales Beispiel zu zeigen.

Beachten Sie auch, dass das obige Beispiel nicht rekursiv ist. Wenn es sich um Dictionarys in Dictionarys handelt, müssen Sie etwas Rekursion verwenden. Sehen Sie die rekursive Funktion, die ich geschrieben habe und die Sie verwenden können:

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 = """
Test1234
3455"""

print xml_to_dict(xml_string)

Hier ist eine Variante, die den Elternschlüssel/-element erhält:

def xml_to_dict(xml_str):
    """XML in ein Dictionary umwandeln, unter Verwendung der XML-Verarbeitungsbibliothek lxml v3.4.2, siehe http://lxml.de/"""
    def xml_to_dict_recursion(xml_object):
        dict_object = xml_object.__dict__
        if not dict_object:  # wenn ein leeres Dictionary zurückgegeben wird
            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)}

Und wenn Sie nur einen Teilbaum zurückgeben und ihn in ein Dictionary konvertieren möchten, können Sie Element.find() verwenden:

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

Es gibt viele Möglichkeiten, dies zu erreichen, aber diese ist großartig, wenn Sie bereits lxml verwenden. In diesem Beispiel wurde lxml-3.4.2 verwendet. Prost!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X