如何用Python将XML中的所有信息转换为字典
假设我有一个这样的XML文件。
<A>
<B>
<C>"blah"</C>
<C>"blah"</C>
</B>
<B>
<C>"blah"</C>
<C>"blah"</C>
</B>
</A>
我需要把这个文件读进一个字典,像这样。
dict["A.B1.C1"] = "blah" dict["A.B1.C2"] = "blah" dict["A.B2.C1"] = "blah" dict["A.B2.C2"] = "blah"
不过字典的格式其实不重要,我只想把所有信息读进Python的变量里。
问题是我不知道这个XML的结构,我只想把所有信息读进一个字典里。
有没有什么方法可以用Python做到这一点呢?
4 个回答
5
我通常使用标准库中的ElementTree模块来解析XML文件。这个模块不会给你一个字典,而是提供一个更有用的DOM结构,这样你可以遍历每个元素及其子元素。
from xml.etree import ElementTree as ET
xml = ET.parse("<path-to-xml-file")
root_element = xml.getroot()
for child in root_element:
...
如果你确实需要把它解析成字典,而不是从DOM树中获取所需的信息,那么可以写一个递归函数,从根节点开始构建字典,代码大概是这样的:
def xml_dict(node, path="", dic =None):
if dic == None:
dic = {}
name_prefix = path + ("." if path else "") + node.tag
numbers = set()
for similar_name in dic.keys():
if similar_name.startswith(name_prefix):
numbers.add(int (similar_name[len(name_prefix):].split(".")[0] ) )
if not numbers:
numbers.add(0)
index = max(numbers) + 1
name = name_prefix + str(index)
dic[name] = node.text + "<...>".join(childnode.tail
if childnode.tail is not None else
"" for childnode in node)
for childnode in node:
xml_dict(childnode, name, dic)
return dic
对于你上面提到的XML,这样处理后会得到一个字典:
{'A1': '\n \n <...>\n',
'A1.B1': '\n \n <...>\n ',
'A1.B1.C1': '"blah"',
'A1.B1.C2': '"blah"',
'A1.B2': '\n \n <...>\n ',
'A1.B2.C1': '"blah"',
'A1.B2.C2': '"blah"'}
(我觉得DOM形式更有用)
5
我通常使用 lxml.objectify 这个库来快速解析XML文件。
对于你的XML字符串,你可以这样做:
from lxml import objectify
root = objectify.fromstring(xml_string)
然后你可以通过字典的方式来获取单独的元素:
value = root["A"][0]["B"][0]["C"][0]
或者,如果你更喜欢这样:
value = root.A[0].B[0].C[0]
6
你可以在Python中使用untangle这个库。untangle.parse()可以把一个XML文档转换成Python对象。
这个方法需要一个XML文件作为输入,然后返回一个Python对象,这个对象就代表了那个XML文档。
我们来看看下面这个XML文件,假设我们把它命名为test_xml.xml。
<A>
<B>
<C>"blah1"</C>
<C>"blah2"</C>
</B>
<B>
<C>"blah3"</C>
<C>"blah4"</C>
</B>
</A>
现在我们来把上面的XML文件转换成一个Python对象,这样就可以访问XML文件中的元素了。
>>>import untangle
>>>input_file = "/home/tests/test_xml.xml" #Full path to your xml file
>>>obj = untangle.parse(input_file)
>>>obj.A.B[0].C[0].cdata
u'"blah1"'
>>> obj.A.B[0].C[1].cdata
u'"blah2"'
>>> obj.A.B[1].C[0].cdata
u'"blah3"'
>>> obj.A.B[1].C[1].cdata
u'"blah4"'