1
\$\begingroup\$

I've written a function that works however I'm sure there is a better way. I need to parse specific tags from an xml document (Microsoft Word docx document.xml).

Here is the general structure of the xml in question.

//A ton of crap
...
<w:tbl>
  <w:tr>
    <w:tc>
      <w:p>
        <w:r>
          <w:t>Data_I_want</w:t>
        </w:r>
      </w:p>
    </w:tc>
  </w:tr>
  <w:tr>
    <w:tc>
      <w:p>
        <w:r>
          <w:t>Data_I_want</w:t>
        </w:r>
      </w:p>
    </w:tc>
  </w:tr>
</w:tbl>
...
// A ton more crap
//Same structure repeats and I need to grab that n number of times where n is unknown.
// Also the order of the data must be preserved within each parent tbl tag.

Here is an excerpt of my code:

def recurse_search_tables(self, xml_data):
    """
    Recursively traverse the xml child nodes..
    """
    tag_base = r'{http://schemas.openxmlformats.org/wordprocessingml/2006/main}'        
    for child in xml_data:
        if child.tag.replace(tag_base,'') == 'tbl':
                for c in child:
                    if c.tag.replace(tag_base,'') == 'tr':
                        for tr in c:
                            if tr.tag.replace(tag_base,'') == 'tc':
                                for tc in tr:
                                    if tc.tag.replace(tag_base,'') == 'p': 
                                        for p in tc:
                                            if p.tag.replace(tag_base,'') == 'r':
                                                for r in p:
                                                    if r.tag.replace(tag_base,'') == 't':
                                                        try:
                                                            self.decide_to_print(r.text.encode('UTF-8'))
                                                        except:
                                                            pass
                                                        finally:
                                                            self.recurse_search_tables(child)
                                                    else:
                                                        self.recurse_search_tables(child)
                                            else:
                                                self.recurse_search_tables(child)
                                    else:
                                        self.recurse_search_tables(child)
                            else:
                                self.recurse_search_tables(child)
                    else:
                        self.recurse_search_tables(child)
        else:
            self.recurse_search_tables(child)

Calling that mess via:

tree = ET.parse('document.xml')
root = tree.getroot()
self.recurse_search_tables(root)

Now like i said, this code works however it isn't the fastest (but is is suitable). How can I improve this?

\$\endgroup\$
  • \$\begingroup\$ Use XPath, it's made for that. \$\endgroup\$ – ferada Mar 4 '15 at 21:22
1
\$\begingroup\$

Thanks to Ferada for the hint. Here is what I was able to replace that monster with. Execution time went from more than 590 seconds to less than 2 seconds.

Note: all of the string replacements were another performance pain point, using a single string is much quicker here.

def recurse_search_tables(self, root):
    # Get individual tables and their children nodes. 
    for table in root.iter(r'{http://schemas.openxmlformats.org/wordprocessingml/2006/main}tbl'):
        for t in table.iter(r'{http://schemas.openxmlformats.org/wordprocessingml/2006/main}t'):
            self.decide_to_print(t.text.encode('UTF-8'))
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.