Recursive XML parsing python using ElementTree

import xml.etree.ElementTree as ET
tree = ET.ElementTree(file='work.xml')

indent = 0
ignoreElems = ['displayNameKey', 'displayName']

def printRecur(root):
    """Recursively prints the tree."""
    if root.tag in ignoreElems:
        return
    print ' '*indent + '%s: %s' % (root.tag.title(), root.attrib.get('name', root.text))
    global indent
    indent += 4
    for elem in root.getchildren():
        printRecur(elem)
    indent -= 4

root = tree.getroot()
printRecur(root)

OUTPUT:

Suite: MainApplication
    Application: Sub Application1
        Category: about
            Category: comms
                Property: copyright
                    Value: 2014
                Property: os
                    Value: Linux 2.6.32-431.29.2.el6.x86_64
            Property: releaseNumber
                Value: 9.1.0.3.0.54

This is closest I could get in 5 minutes. You should just recursively call a processor function and that would take care. You can improve on from this point :)


You can also define handler function for each tag and put all of them in a dictionary for easy lookup. Then you can check if you have an appropriate handler function for that tag, then call that else just continue with blindly printing. For example:

HANDLERS = {
    'property': 'handle_property',
    <tag_name>: <handler_function>
}

def handle_property(root):
    """Takes property root element and prints the values."""
    data = ' '*indent + '%s: %s ' % (root.tag.title(), root.attrib['name'])
    values = []
    for elem in root.getchildren():
        if elem.tag == 'value':
            values.append(elem.text)
    print data + '| %s' % (', '.join(values))

# printRecur would get modified accordingly.
def printRecur(root):
    """Recursively prints the tree."""
    if root.tag in ignoreElems:
        return

    global indent
    indent += 4

    if root.tag in HANDLERS:
        handler = globals()[HANDLERS[root.tag]]
        handler(root)
    else:
        print ' '*indent + '%s: %s' % (root.tag.title(), root.attrib.get('name', root.text))
        for elem in root.getchildren():
            printRecur(elem)

    indent -= 4

Output with above:

Suite: MainApplication
    Application: Sub Application1
        Category: about
            Category: comms
                Property: copyright | 2014
                Property: os | Linux 2.6.32-431.29.2.el6.x86_64
            Property: releaseNumber | 9.1.0.3.0.54

I find this very useful rather than putting tons of if/else in the code.