2009-11-23 37 views
55

Me está costando encontrar un buen ejemplo básico de cómo analizar XML en Python usando Element Tree. Según lo que puedo encontrar, esta parece ser la biblioteca más fácil de usar para analizar XML. Este es un ejemplo del XML estoy trabajando con:Analizando XML en Python usando el ejemplo de ElementTree

<timeSeriesResponse> 
    <queryInfo> 
     <locationParam>01474500</locationParam> 
     <variableParam>99988</variableParam> 
     <timeParam> 
      <beginDateTime>2009-09-24T15:15:55.271</beginDateTime> 
      <endDateTime>2009-11-23T15:15:55.271</endDateTime> 
     </timeParam> 
    </queryInfo> 
    <timeSeries name="NWIS Time Series Instantaneous Values"> 
     <values count="2876"> 
      <value dateTime="2009-09-24T15:30:00.000-04:00" qualifiers="P">550</value> 
      <value dateTime="2009-09-24T16:00:00.000-04:00" qualifiers="P">419</value> 
      <value dateTime="2009-09-24T16:30:00.000-04:00" qualifiers="P">370</value> 
      ..... 
     </values> 
    </timeSeries> 
</timeSeriesResponse> 

soy capaz de hacer lo que necesito, utilizando un método de codificación fija. Pero necesito que mi código sea un poco más dinámico. Aquí es lo que ha funcionado:

tree = ET.parse(sample.xml) 
doc = tree.getroot() 

timeseries = doc[1] 
values = timeseries[2] 

print child.attrib['dateTime'], child.text 
#prints 2009-09-24T15:30:00.000-04:00, 550 

Aquí hay un par de cosas que he intentado, ninguno de ellos trabajaba, informando de que no podían encontrar series de tiempo (o cualquier otra cosa que intentó):

tree = ET.parse(sample.xml) 
tree.find('timeSeries') 

tree = ET.parse(sample.xml) 
doc = tree.getroot() 
doc.find('timeSeries') 

Básicamente, quiero cargar el archivo xml, buscar la etiqueta timeSeries e iterar a través de las etiquetas de valor, devolviendo dateTime y el valor de la etiqueta; todo lo que estoy haciendo en el ejemplo anterior, pero no codificando con fuerza las secciones de xml que me interesan. ¿Alguien puede indicarme algunos ejemplos o darme algunas sugerencias sobre cómo solucionar esto?


Gracias por la ayuda. Sin embargo, al usar las dos sugerencias a continuación trabajadas en el archivo de muestra que proporcioné, no funcionaron en el archivo completo. Aquí está el error que recibo del archivo real cuando utilizo el método de Ed Carrel:

(<type 'exceptions.AttributeError'>, AttributeError("'NoneType' object has no attribute 'attrib'",), <traceback object at 0x011EFB70>) 

que pensé había algo en el archivo real que no le gustó, así que incremently quitado cosas, hasta que fermentó. Estas son las líneas que he cambiado:

originally: <timeSeriesResponse xsi:schemaLocation="a URL I removed" xmlns="a URL I removed" xmlns:xsi="a URL I removed"> 
changed to: <timeSeriesResponse> 

originally: <sourceInfo xsi:type="SiteInfoType"> 
changed to: <sourceInfo> 

originally: <geogLocation xsi:type="LatLonPointType" srs="EPSG:4326"> 
changed to: <geogLocation> 

Al eliminar los atributos que tienen 'xsi: ...' se solucionó el problema. ¿El XML 'xsi: ...' no es válido? Será difícil para mí eliminar estos programáticamente. ¿Alguna solución sugerida?

Aquí está el archivo XML completo: http://www.sendspace.com/file/lofcpt


Cuando originalmente esta pregunta, yo estaba al tanto de espacios de nombres en XML. Ahora que sé lo que está pasando, no tengo que eliminar los atributos "xsi", que son las declaraciones del espacio de nombres. Simplemente los incluyo en mis búsquedas xpath. Consulte this page para obtener más información sobre los espacios de nombres en lxml.

+0

Le sugiero que consulte el módulo 'etree' proporcionado por' lxml'? Lo descubrí recientemente y he encontrado que es muy superior a ElementTree. Fue escrito como un reemplazo que emula completamente ElementTree. – jathanism

+0

Terminé yendo con lxml, ya que era un poco más fácil trabajar con él, pero sigo teniendo el problema descrito anteriormente. Para una reparación, escaneo el archivo xml de antemano y elimino todas las instancias de "xsi: tipo". Los métodos descritos en las respuestas a continuación funcionan bien. – Casey

Respuesta

40

Así que tienen elementtree 1.2.6 en mi caja de ahora, y corría el siguiente código XML contra el trozo informados:

import elementtree.ElementTree as ET 

tree = ET.parse("test.xml") 
doc = tree.getroot() 
thingy = doc.find('timeSeries') 

print thingy.attrib 

y tiene la siguiente vuelta:

{'name': 'NWIS Time Series Instantaneous Values'} 

Parece haber encontrado el elemento timeSeries sin necesidad de usar índices numéricos.

Lo que sería útil ahora es saber a qué te refieres cuando dices "no funciona". Como funciona para mí con la misma información, es poco probable que ElementTree se rompa de alguna manera obvia. Actualice su pregunta con cualquier mensaje de error, trazas inversas o cualquier cosa que pueda proporcionar para ayudarnos a ayudarlo.

+28

Para las nuevas versiones de Python, la importación ha cambiado a: import xml.etree.ElementTree como ET – Louis

+0

@Louis: ¿qué quiere decir con 'las nuevas versiones de Python'? –

+0

@Monica Heddneck: Como este comentario tiene más de seis años, debería decir que cada python por encima de 2.3 ... – Louis

18

Si entiendo bien su pregunta:

for elem in doc.findall('timeSeries/values/value'): 
    print elem.get('dateTime'), elem.text 

o si lo prefiere (y si sólo hay una ocurrencia de timeSeries/values:

values = doc.find('timeSeries/values') 
for value in values: 
    print value.get('dateTime'), elem.text 

El método findall() devuelve una lista de todos los elementos coincidentes , mientras que find() devuelve solo el primer elemento coincidente. El primer ejemplo recorre todos los elementos encontrados, el segundo pasa sobre los elementos secundarios del elemento values, en este caso conduce a la misma resultado.

No veo dónde viene el problema de no encontrar timeSeries. ¿Tal vez olvidaste la llamada getroot()? (tenga en cuenta que en realidad no lo necesita porque puede trabajar desde el árbol de elementos también, si cambia la expresión de ruta a, por ejemplo, /timeSeriesResponse/timeSeries/values o //timeSeries/values)

+0

Funciona muy bien. Lo usé con el módulo 'from lxml import etree'. 'doc = etree.parse ('test.xml')' –

Cuestiones relacionadas