Python3 将 XML 解析为字典
Python3 parse XML into dictionary
原来的post似乎太模糊了,所以我缩小了这个post的重点。我有一个 XML 文件,我想从中提取特定分支的值,但我很难理解如何有效地导航 XML 路径。考虑下面的 XML 文件。有几个 <mi>
分支。我想存储某些分支的 <r>
值,但不存储其他分支。在这个例子中,我想要 counter1 和 counter3 的 <r>
值,而不是 counter2.
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="Data.xsl" ?>
<!DOCTYPE mdc SYSTEM "Data.dtd">
<mdc xmlns:HTML="http://www.w3.org/TR/REC-xml">
<mfh>
<vn>TEST</vn>
<cbt>20140126234500.0+0000</cbt>
</mfh>
<mi>
<mts>20140126235000.0+0000</mts>
<mt>counter1</mt>
<mv>
<moid>DEFAULT</moid>
<r>58</r>
</mv>
</mi>
<mi>
<mts>20140126235000.0+0000</mts>
<mt>counter2</mt>
<mv>
<moid>DEFAULT</moid>
<r>100</r>
</mv>
</mi>
<mi>
<mts>20140126235000.0+0000</mts>
<mt>counter3</mt>
<mv>
<moid>DEFAULT</moid>
<r>7</r>
</mv>
</mi>
</mdc>
据此我想用以下内容构建一个元组:
('20140126234500.0+0000', 58, 7)
其中 20140126234500.0+0000 取自 <cbt>
,58 取自具有 <mt>counter1</mt>
的 <mi>
元素的 <r>
值,而 7 取自 <mi>
具有 <mt>counter3</mt>
.
的元素
我想使用 xml.etree.cElementTree
,因为它似乎是标准的,而且应该足以满足我的目的。但是我在导航树和提取我需要的值时遇到了困难。以下是我尝试过的一些方法。
try:
import xml.etree.cElementTree as ET
except ImportError:
import xml.etree.ElementTree as ET
tree = ET.ElementTree(file='Data.xml')
root = tree.getroot()
for mi in root.iter('mi'):
print(mi.tag)
for mt in mi.findall("./mt") if mt.value == 'counter1':
print(mi.find("./mv/r").value) #I know this is invalid syntax, but it's what I want to do :)
从伪代码的角度来看,我想做的是:
find the <cbt> value and store it in the first position of the tuple.
find the <mi> element where <mt>counter1</mt> exists and store the <r> value in the second position of the tuple.
find the <mi> element where <mt>counter3</mt> exists and store the <r> value in the third position of the tuple.
我不清楚何时使用 element.iter()
或 element.findall()
。另外,我没有在函数中使用 XPath
或能够提取我需要的信息的好运气。
谢谢,
生锈
开始于:
import xml.etree.cElementTree as ET # or with try/except as per your edit
xml_data1 = """<?xml version="1.0"?> and the rest of your XML here"""
tree = ET.fromstring(xml_data) # or `ET.parse(<filename>)`
xml_dict = {}
现在 tree
有 xml 树,xml_dict
将是您尝试获取结果的字典。
# first get the key & val for 'cbt'
cbt_val = tree.find('mfh').find('cbt').text
xml_dict['cbt'] = cbt_val
计数器在 'mi'
:
for elem in tree.findall('mi'):
counter_name = elem.find('mt').text # key
counter_val = elem.find('mv').find('r').text # value
xml_dict[counter_name] = counter_val
此时xml_dict
为:
>>> xml_dict
{'counter2': '100', 'counter1': '58', 'cbt': '20140126234500.0+0000', 'counter3': '7'}
一些缩短,但可能不那么可读:for elem in tree.findall('mi'):
循环中的代码可以是:
xml_dict[elem.find('mt').text] = elem.find('mv').find('r').text
# that combines the key/value extraction to one line
或者更进一步,构建 xml_dict
只需两行即可完成,首先是计数器,然后是 cbt
:
xml_dict = {elem.find('mt').text: elem.find('mv').find('r').text for elem in tree.findall('mi')}
xml_dict['cbt'] = tree.find('mfh').find('cbt').text
编辑:
From the docs, Element.findall()
仅查找带有标签且是当前元素的直接子元素的元素。
find()
只找到第一个直接子节点。
iter()
递归遍历所有元素。
原来的post似乎太模糊了,所以我缩小了这个post的重点。我有一个 XML 文件,我想从中提取特定分支的值,但我很难理解如何有效地导航 XML 路径。考虑下面的 XML 文件。有几个 <mi>
分支。我想存储某些分支的 <r>
值,但不存储其他分支。在这个例子中,我想要 counter1 和 counter3 的 <r>
值,而不是 counter2.
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="Data.xsl" ?>
<!DOCTYPE mdc SYSTEM "Data.dtd">
<mdc xmlns:HTML="http://www.w3.org/TR/REC-xml">
<mfh>
<vn>TEST</vn>
<cbt>20140126234500.0+0000</cbt>
</mfh>
<mi>
<mts>20140126235000.0+0000</mts>
<mt>counter1</mt>
<mv>
<moid>DEFAULT</moid>
<r>58</r>
</mv>
</mi>
<mi>
<mts>20140126235000.0+0000</mts>
<mt>counter2</mt>
<mv>
<moid>DEFAULT</moid>
<r>100</r>
</mv>
</mi>
<mi>
<mts>20140126235000.0+0000</mts>
<mt>counter3</mt>
<mv>
<moid>DEFAULT</moid>
<r>7</r>
</mv>
</mi>
</mdc>
据此我想用以下内容构建一个元组:
('20140126234500.0+0000', 58, 7)
其中 20140126234500.0+0000 取自 <cbt>
,58 取自具有 <mt>counter1</mt>
的 <mi>
元素的 <r>
值,而 7 取自 <mi>
具有 <mt>counter3</mt>
.
我想使用 xml.etree.cElementTree
,因为它似乎是标准的,而且应该足以满足我的目的。但是我在导航树和提取我需要的值时遇到了困难。以下是我尝试过的一些方法。
try:
import xml.etree.cElementTree as ET
except ImportError:
import xml.etree.ElementTree as ET
tree = ET.ElementTree(file='Data.xml')
root = tree.getroot()
for mi in root.iter('mi'):
print(mi.tag)
for mt in mi.findall("./mt") if mt.value == 'counter1':
print(mi.find("./mv/r").value) #I know this is invalid syntax, but it's what I want to do :)
从伪代码的角度来看,我想做的是:
find the <cbt> value and store it in the first position of the tuple.
find the <mi> element where <mt>counter1</mt> exists and store the <r> value in the second position of the tuple.
find the <mi> element where <mt>counter3</mt> exists and store the <r> value in the third position of the tuple.
我不清楚何时使用 element.iter()
或 element.findall()
。另外,我没有在函数中使用 XPath
或能够提取我需要的信息的好运气。
谢谢, 生锈
开始于:
import xml.etree.cElementTree as ET # or with try/except as per your edit
xml_data1 = """<?xml version="1.0"?> and the rest of your XML here"""
tree = ET.fromstring(xml_data) # or `ET.parse(<filename>)`
xml_dict = {}
现在 tree
有 xml 树,xml_dict
将是您尝试获取结果的字典。
# first get the key & val for 'cbt'
cbt_val = tree.find('mfh').find('cbt').text
xml_dict['cbt'] = cbt_val
计数器在 'mi'
:
for elem in tree.findall('mi'):
counter_name = elem.find('mt').text # key
counter_val = elem.find('mv').find('r').text # value
xml_dict[counter_name] = counter_val
此时xml_dict
为:
>>> xml_dict
{'counter2': '100', 'counter1': '58', 'cbt': '20140126234500.0+0000', 'counter3': '7'}
一些缩短,但可能不那么可读:for elem in tree.findall('mi'):
循环中的代码可以是:
xml_dict[elem.find('mt').text] = elem.find('mv').find('r').text
# that combines the key/value extraction to one line
或者更进一步,构建 xml_dict
只需两行即可完成,首先是计数器,然后是 cbt
:
xml_dict = {elem.find('mt').text: elem.find('mv').find('r').text for elem in tree.findall('mi')}
xml_dict['cbt'] = tree.find('mfh').find('cbt').text
编辑:
From the docs, Element.findall()
仅查找带有标签且是当前元素的直接子元素的元素。
find()
只找到第一个直接子节点。
iter()
递归遍历所有元素。