2016-10-11 48 views
-1

看起来原来的帖子太模糊了,所以我正在缩小这篇文章的重点。我有一个XML文件,我想从特定分支中提取值,并且我很难理解如何有效地导航XML路径。考虑下面的XML文件。有几个<mi>分支。我想存储某些分支的价值<r>,但不是其他分支。在这个例子中,我想要counter1和counter3的<r>值,但不是counter2。Python3将XML解析为字典

<?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从的<r>值取具有<mt>counter1</mt>和7的<mi>元素取自具有<mt>counter3</mt><mi>元素。

我想使用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,或者能够提取我所需要的信息。

感谢, 生锈

+1

发布您尝试过的内容。顺便说一下,定期'dict'没有排序。根据您的绘图软件,您可能需要维护两个并行列表或可能是用于排序的元组列表。 – tdelaney

+0

...以及一个人如何绘制计数器名称。你想要值吗? – tdelaney

+0

我已经尝试了几件事情,但大多数时候我甚至不知道如何在Python中进行操作。我会试着发布一些迄今为止我所做的。是的,我想绘制r值。并感谢您对替代方法的建议。这就是为什么我包含了关于想要绘制这些信息的原因。我不确定我是否正确地使用词典来解决这个问题。如果你可以发表一些关于如何使用元组的细节,我会非常感激。 –

回答

1

与开始:

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 docsElement.findall()只查找具有标签的元素是当前元素的直接子元素。

find()只找到第一个直接孩子。

iter()以递归方式迭代所有元素。

+0

谢谢!这看起来非常有用。我会尽快进行测试。 –

+0

我必须改变你的例子中的for循环到'forem in tree.find('md')。findall('mi'):'否则,它不会找到任何元素。这是预期的吗? findall不是递归的吗?编辑 - 我看到你已经回答了。它只能找到当前元素的直接子元素。 –

+0

我没有在您的示例x​​ml中看到任何名为'md'的节点/标记。当你做'ET.fromstring(xml_data)',那[已经给你根](https://docs.python.org/3/library/xml.etree.elementtree.html#parsing-xml),' mdc'在这种情况下。对于'ET.parse()',你需要做'tree.getroot()',然后给你'mdc'。 'for''循环的'tree.find('md')'部分为你做了。顺便说一句,请参阅[如何接受答案的工作?](http://meta.stackexchange.com/a/5235/193893)&[我应该怎么做当有人回答我的问题?](http://stackoverflow.com/help/someone-answers) – aneroid