Python lxml findall con múltiples espacios de nombres

Estoy tratando de analizar un documento XML con múltiples espacios de nombres con lxml, y estoy atascado en obtener el método findall () para devolver algo.

Mi XML:

  100_0000100004_3788_Resource-0.customId_WSx Data Precip Type   60 Valid 2016-04-20T12:40:00Z      

Mi código:

 from lxml import etree from pprint import pprint RSPxmlFile = '/home/user/Desktop/100_0000100004_3788_20160420144011263_records.xml' with open (RSPxmlFile, 'rt') as f: tree = etree.parse(f) root = tree.getroot() for node in tree.findall('MeasurementRecords', root.nsmap): print node print "parameter = ", node.text 

Da:

 ValueError: empty namespace prefix is not supported in ElementPath 

Algunos experimentos que he probado después de leer esto :

 >>> root.nsmap {'xsi': 'http://www.w3.org/2001/XMLSchema-instance', None: http://www.company.com/common/rsp/2012/07'} >>> nsmap['foo']=nsmap[None] >>> nsmap.pop(None) 'http://www.company.com/common/rsp/2012/07' >>> nsmap {'xsi': 'http://www.w3.org/2001/XMLSchema-instance', 'foo': 'http://www.company.com/common/rsp/2012/07'} >>> tree.xpath("//MeasurementRecords", namespaces=nsmap) [] >>> tree.xpath('/foo:MeasurementRecords', namespaces=nsmap) [] >>> tree.xpath('/foo:MeasurementRecords/HistoryRecords', namespaces=nsmap) [] 

Pero eso no pareció ayudar.

Así que, más experimentos:

 >>> tree.findall('//{http://www.company.com/common/rsp/2012/07}MeasurementRecords') [] >>> print root  >>> print tree  >>> for node in tree.iter(): ... print node ...    ...etc... >>> tree.findall("//HistoryRecords", namespaces=nsmap) [] >>> tree.findall("//foo:MeasurementRecords/HistoryRecords", namespaces=nsmap) [] 

Estoy perplejo. No tengo idea de lo que está mal.

Si empiezas con esto:

 >>> tree = etree.parse(open('data.xml')) >>> root = tree.getroot() >>> 

Esto no podrá encontrar ningún elemento …

 >>> root.findall('{http://www.company.com/common/rsp/2012/07}MeasurementRecords') [] 

… pero eso es porque la root es un elemento MeasurementRecords ; no contiene ningún elemento de MeasurementRecords . Por otro lado, lo siguiente funciona bien:

 >>> root.findall('{http://www.company.com/common/rsp/2012/07}HistoryRecords') [] >>> 

Usando el método xpath , podrías hacer algo como esto:

 >>> nsmap={'a': 'http://www.company.com/common/rsp/2012/07', ... 'b': 'http://www.w3.org/2001/XMLSchema-instance'} >>> root.xpath('//a:HistoryRecords', namespaces=nsmap) [] 

Asi que:

  • Los métodos findall y find requieren {...namespace...}ElementName syntax {...namespace...}ElementName .
  • El método xpath requiere prefijos de espacio de nombres ( ns:ElementName ), que busca en el mapa de namespaces provisto. El prefijo no tiene que coincidir con el prefijo usado en el documento original, pero la url del espacio de nombres debe coincidir.

Así que esto funciona:

 >>> root.find('{http://www.company.com/common/rsp/2012/07}HistoryRecords/{http://www.company.com/common/rsp/2012/07}ValueItemId')  

O esto funciona:

 >>> root.xpath('/a:MeasurementRecords/a:HistoryRecords/a:ValueItemId',namespaces=nsmap) []