How do I use xml namespaces with find/findall in lxml?
Question: I'm trying to parse content in an OpenOffice ODS spreadsheet. The ods format
is essentially just a zipfile with a number of documents. The content of the
spreadsheet is stored in 'content.xml'.

    
    
    import zipfile
    from lxml import etree
    
    zf = zipfile.ZipFile('spreadsheet.ods')
    root = etree.parse(zf.open('content.xml'))
    

The content of the spreadsheet is in a cell:

    
    
    table = root.find('.//{urn:oasis:names:tc:opendocument:xmlns:table:1.0}table')
    

We can also go straight for the rows:

    
    
    rows = root.findall('.//{urn:oasis:names:tc:opendocument:xmlns:table:1.0}table-row')
    

The individual elements know about the namespaces:

    
    
    >>> table.nsmap['table']
    'urn:oasis:names:tc:opendocument:xmlns:table:1.0'
    

How do I use the namespaces directly in find/findall?

The obvious solution does not work.

Trying to get the rows from the table:

    
    
    >>> root.findall('.//table:table')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "lxml.etree.pyx", line 1792, in lxml.etree._ElementTree.findall (src/lxml/lxml.etree.c:41770)
      File "lxml.etree.pyx", line 1297, in lxml.etree._Element.findall (src/lxml/lxml.etree.c:37027)
      File "/usr/lib/python2.6/dist-packages/lxml/_elementpath.py", line 225, in findall
        return list(iterfind(elem, path))
      File "/usr/lib/python2.6/dist-packages/lxml/_elementpath.py", line 200, in iterfind
        selector = _build_path_iterator(path)
      File "/usr/lib/python2.6/dist-packages/lxml/_elementpath.py", line 184, in _build_path_iterator
        selector.append(ops[token[0]](_next, token))
    KeyError: ':'
    


Answer: If `root.nsmap` contains the `table` namespace prefix then you could:

    
    
    root.xpath('.//table:table', namespaces=root.nsmap)
    

`findall(path)` accepts `{namespace}name` syntax instead of `namespace:name`.
Therefore `path` should be preprocessed using namespace dictionary to the
`{namespace}name` form before passing it to `findall()`.

