将xml转换为python dict
Posted
技术标签:
【中文标题】将xml转换为python dict【英文标题】:convert xml to python dict 【发布时间】:2013-06-15 03:41:04 【问题描述】:我正在尝试创建一个 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)
【问题讨论】:
这个问题之前似乎已经回答过了:***.com/questions/2148119/… 你想要的输出是什么? @Josh 我不明白你的想法朋友 @robjohncox 之前在那里找到了解决方案,但我没有肯定 @alecxe 类似这样:"to":"Tove", "from":"Jani", "heading":"Reminder", "body":"别忘了我这个周末!” 【参考方案1】:你应该结帐
https://github.com/martinblech/xmltodict
我认为它是我见过的 xml 到 dict 的最佳标准处理程序之一。
但是我应该警告你 xml 和 dict 不是绝对兼容的数据结构
【讨论】:
感谢您的回答。我猜也不是完全兼容的结构,而且没有像过去那样快的解决方案。 @funktasmas:对于简单情况,唯一的大问题是 XML 节点可以具有属性以及子节点,您必须决定如何表示。xmltodict
将属性表示为名称带有@
前缀的节点,这是解决问题的一种方法,但还有其他可能性——例如,您可以使用__getitem__
处理节点,使用__getattr__
处理属性。
【参考方案2】:
你可以使用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'
【讨论】:
感谢您的帮助,我真的很感激,但我仍然认为或者更确切地说,看看它在没有额外模块的情况下如何执行,无论如何我都会尝试。 @funktasmas:如果您想了解如何在没有附加模块的情况下进行操作,为什么不查看xmltodict
的源代码?这是几百行干净、注释良好的 Python 代码。而且它肯定会比有人想出的任何快速而肮脏的黑客来回答 SO 更好。
@abarnert 只是看看他们是如何开发模块的,也许这是一个很好的开始。
@funktasmas:考虑到模块的许可和开发历史,可能最好的开始方式就是分叉它并开始使用你的分叉。这样一来,如果您想出了原始文件中缺少的任何内容,并且想要与世界分享,您只需向上游提交一个拉取请求。
@abarnert 如果我为此开发了一些代码,我可以毫无问题地与社区分享任何信息。【参考方案3】:
您可以使用lxml library。使用 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 对象转换为 dict 会返回一个 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 字符串是 paymentech 支付网关的响应,只是为了展示一个真实世界的例子。
还要注意上面的例子不是递归的,所以如果字典中有字典,你必须做一些递归。看看我写的你可以使用的递归函数:
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)
如果你只想返回一个子树并将其转换为dict,你可以使用Element.find():
xml_obj.find('.//') # lxml.objectify.ObjectifiedElement instance
有很多选项可以实现这一点,但如果您已经在使用 lxml,这个选项非常棒。在这个例子中使用了 lxml-3.4.2。干杯!
【讨论】:
如果你想要一个真正的 python 字典(不是 lxml 对象的字典),那么将xml_to_dict_recursion
更新为 return xml_object.pyval
【参考方案4】:
您可能认为到现在我们已经对这个问题有了一个很好的答案,但我们显然没有。 在查看了关于 *** 的半打类似问题后,这对我有用:
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)
希望对你有帮助:-)
【讨论】:
这对我有用。我必须在通话中将.getroot()
添加到tree
,如etree2dict(tree.getroot())
。也许这是因为我从文件而不是从字符串中读取 XML?无论如何,很好的答案。以上是关于将xml转换为python dict的主要内容,如果未能解决你的问题,请参考以下文章
使用 Python 或 XSLT 将复杂的 XML 转换为 CSV
在 python 中使用 Argparse 将 xml 转换为 csv
python [xml文件到voc的csv文件]将voc标签转换为xml格式为csv格式#python #csv #xml