Python3 parse XML into dictionary
<p>It seems the original post was too vague, so I'm narrowing down the focus of this post.  I have an XML file from which I want to pull values from specific branches, and I am having difficulty in understanding how to effectively navigate the XML paths.  Consider the XML file below.  There are several <code>&lt;mi&gt;</code> branches.  I want to store the <code>&lt;r&gt;</code> value of certain branches, but not others.  In this example, I want the <code>&lt;r&gt;</code> values of counter1 and counter3, but not counter2.</p>

<pre><code>&lt;?xml version="1.0"?&gt;
&lt;?xml-stylesheet type="text/xsl" href="Data.xsl" ?&gt;
&lt;!DOCTYPE mdc SYSTEM "Data.dtd"&gt;
&lt;mdc xmlns:HTML="http://www.w3.org/TR/REC-xml"&gt;
&lt;mfh&gt;
&lt;vn&gt;TEST&lt;/vn&gt;
&lt;cbt&gt;20140126234500.0+0000&lt;/cbt&gt;
&lt;/mfh&gt;
&lt;mi&gt;
    &lt;mts&gt;20140126235000.0+0000&lt;/mts&gt;
    &lt;mt&gt;counter1&lt;/mt&gt;
    &lt;mv&gt;
        &lt;moid&gt;DEFAULT&lt;/moid&gt;
        &lt;r&gt;58&lt;/r&gt;
    &lt;/mv&gt;
&lt;/mi&gt;
&lt;mi&gt;
    &lt;mts&gt;20140126235000.0+0000&lt;/mts&gt;
    &lt;mt&gt;counter2&lt;/mt&gt;
    &lt;mv&gt;
        &lt;moid&gt;DEFAULT&lt;/moid&gt;
        &lt;r&gt;100&lt;/r&gt;
    &lt;/mv&gt;
&lt;/mi&gt;
&lt;mi&gt;
    &lt;mts&gt;20140126235000.0+0000&lt;/mts&gt;
    &lt;mt&gt;counter3&lt;/mt&gt;
    &lt;mv&gt;
        &lt;moid&gt;DEFAULT&lt;/moid&gt;
        &lt;r&gt;7&lt;/r&gt;
    &lt;/mv&gt;
&lt;/mi&gt;
&lt;/mdc&gt;
</code></pre>

<p>From that I would like to build a tuple with the following:
('20140126234500.0+0000', 58, 7)
where 20140126234500.0+0000 is taken from <code>&lt;cbt&gt;</code>, 58 is taken from the <code>&lt;r&gt;</code> value of the <code>&lt;mi&gt;</code> element that has <code>&lt;mt&gt;counter1&lt;/mt&gt;</code> and 7 is taken from the <code>&lt;mi&gt;</code> element that has <code>&lt;mt&gt;counter3&lt;/mt&gt;</code>.</p>

<p>I would like to use <code>xml.etree.cElementTree</code> since it seems to be standard and should be more than capable for my purposes.  But I am having difficulty in navigating the tree and extracting the values I need.  Below is some of what I have tried.</p>

<pre><code>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 :)
</code></pre>

<p>From a pseudo code standpoint, what I am wanting to do is:</p>

<pre><code>find the &lt;cbt&gt; value and store it in the first position of the tuple.
find the &lt;mi&gt; element where &lt;mt&gt;counter1&lt;/mt&gt; exists and store the &lt;r&gt; value in the second position of the tuple.
find the &lt;mi&gt; element where &lt;mt&gt;counter3&lt;/mt&gt; exists and store the &lt;r&gt; value in the third position of the tuple.
</code></pre>

<p>I'm not clear when to use <code>element.iter()</code> or <code>element.findall()</code>.  Also, I'm not having the best of luck with using <code>XPath</code> within the functions, or being able to extract the info I'm needing.</p>

<p>Thanks,
Rusty</p>

<p>Starting with:</p>

<pre><code>import xml.etree.cElementTree as ET  # or with try/except as per your edit

xml_data1 = """&lt;?xml version="1.0"?&gt; and the rest of your XML here"""
tree = ET.fromstring(xml_data)  # or `ET.parse(&lt;filename&gt;)`
xml_dict = {}
</code></pre>

<p>Now <code>tree</code> has the xml tree and <code>xml_dict</code> will be the dictionary you're trying to get the result.</p>

<pre><code># first get the key &amp; val for 'cbt'
cbt_val = tree.find('mfh').find('cbt').text
xml_dict['cbt'] = cbt_val
</code></pre>

<p>The counters are in <code>'mi'</code>:</p>

<pre><code>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
</code></pre>

<p>At this point, <code>xml_dict</code> is:</p>

<pre><code>&gt;&gt;&gt; xml_dict
{'counter2': '100', 'counter1': '58', 'cbt': '20140126234500.0+0000', 'counter3': '7'}
</code></pre>

<hr>

<p>Some shortening, though possibly not as read-able: the code in the <code>for elem in tree.findall('mi'):</code> loop can be:</p>

<pre><code>xml_dict[elem.find('mt').text] = elem.find('mv').find('r').text
# that combines the key/value extraction to one line
</code></pre>

<p>Or further, building the <code>xml_dict</code> can be done in just two lines with the counters first and <code>cbt</code> after:</p>

<pre><code>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
</code></pre>

<hr>

<p><em>Edit:</em></p>

<p><a href="https://docs.python.org/3/library/xml.etree.elementtree.html#finding-interesting-elements" rel="nofollow">From the docs</a>, <a href="https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.findall" rel="nofollow"><code>Element.findall()</code></a> finds only elements with a tag which are direct children of the current element.</p>

<p><code>find()</code> only finds the first direct child.</p>

<p><a href="https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.iter" rel="nofollow"><code>iter()</code></a> iterates over all the elements recursively.</p>

python xml elementtree