将xml转换为python dict

将xml转换为python dict,python,xml,parsing,dictionary,xml-parsing,Python,Xml,Parsing,Dictionary,Xml Parsing,我正试图创建一个dict类来处理xml,但遇到了问题,我真的没有办法了。如果有人能在这个问题上提供指导,那就太好了 迄今开发的代码: class XMLResponse(dict): def __init__(self, xml): self.result = True self.message = '' pass def __setattr__(self, name, val): self[name] = val

我正试图创建一个dict类来处理xml,但遇到了问题,我真的没有办法了。如果有人能在这个问题上提供指导,那就太好了

迄今开发的代码:

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)
类XMLResponse(dict):
定义初始化(self,xml):
self.result=True
self.message=“”
通过
定义设置属性(self、name、val):
self[name]=val
def _ugetattr _;(self,name):
如果名称在self中:
返回自我[姓名]
一无所获
message=“本周末不要忘记我!”
XMLResponse(消息)
您应该结帐

我认为它是我所见过的最好的xml口述标准处理程序之一

但是,我应该警告您,xml和dict不是绝对兼容的数据结构

您可以使用模块:

如果顺序不重要,可以将其转换为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'}
您可以使用。使用
objectify.fromstring
将字符串转换为xml对象,然后查找objects dir方法。例如:

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__
我使用的xml字符串是paymentech payments gateway的响应,只是为了展示一个真实的示例

还请注意,上面的示例不是递归的,因此如果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)
如果只想返回子树并将其转换为dict,可以使用Element.find():


有许多选项可以实现这一点,但是如果您已经在使用lxml,那么这一个就很好了。在本例中使用了lxml-3.4.2。干杯

你可能认为现在我们已经有了一个很好的答案,但显然我们没有。 在回顾了六个关于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)
从lxml导入etree
message=““ToveJaniReminderDon这个周末别忘了我!”
tree=etree.fromstring(消息)
etree2dict(树)

希望有帮助:-)

这个问题以前似乎已经得到了回答:你想要的结果是什么?@Josh我不明白你的想法friend@robjohncox以前在那里找到了解决方案,但我没有positive@alecxe类似这样的:{“to”:“Tove”,“from”:“Jani”,“heading”:“remention”,“body”:“这个周末别忘了我!”谢谢你的回答。我想也没有完全兼容的结构,而且没有解决方案能像过去那样快。@funktasmas:简单情况下唯一的大问题是XML节点可以有属性和子节点,您必须决定如何表示它们
xmltodict
将属性表示为名称上带有
@
前缀的节点,这是解决此问题的一种方法,但也有其他可能性,例如,您可以使用
\uu getitem\uuuuuu
处理节点,使用
\uu getattr\uuuuuu
处理attr。感谢您的帮助,我非常感谢,但我仍然认为,或者更确切地说,是看它在没有附加模块的情况下是如何运行的,我还是会试试看。@funktasmas:如果您想了解如何在没有附加模块的情况下运行,为什么不查看
xmltodict
的源代码?这是几百行干净、注释良好的Python代码。这肯定会比其他人想出的任何快速而肮脏的破解方法都要好。@abarnert刚刚看到他们是如何开发这个模块的,也许这是一个很好的开始。@funktasmas:考虑到这个模块的许可和开发历史,最好的开始方法可能就是用叉子叉它,然后开始玩你的叉子。那样的话,如果你找到了原始版本中缺少的任何东西,并且你想与全世界分享,你可以向上游提交一个拉回请求。@abarnert如果我为此开发了一些代码,我可以与社区分享任何信息。这对我来说很有效。我必须在调用中将
.getroot()
添加到
树中
,就像在
etree2dict(tree.getroot())
中一样。也许这是因为我从文件而不是字符串中读取XML?在任何情况下,答案都很好。如果您想要一个真正的python dict(而不是lxml对象的dict),那么将
xml\u更新为
return xml\u object.pyval
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)}
xml_obj.find('.//')  # lxml.objectify.ObjectifiedElement instance
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)