Xmlを処理するために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)
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'}
これまでにこれに対する良い答えがあると思うかもしれませんが、明らかにそうではありませんでした。 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)
それが役に立てば幸い :-)
チェックアウトする必要があります
https://github.com/martinblech/xmltodict
私が見た中で、xmlがdictを実行するための最良の標準ハンドラーの1つだと思います。
ただし、xmlとdictは完全に互換性のあるデータ構造ではないことを警告する必要があります
lxmlライブラリ を使用できます。 objectify.fromstring
を使用して文字列をxmlオブジェクトに変換してから、objectsdirメソッドを検索します。例えば:
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ペイメントゲートウェイからの応答です。
また、上記の例は再帰的ではないため、dict内にdictがある場合は、再帰を実行する必要があることにも注意してください。私が書いた、使用できる再帰関数を参照してください。
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が使用されました。乾杯!