web-dev-qa-db-fra.com

Analyser XML dans Python en utilisant un exemple ElementTree

J'ai de la difficulté à trouver un bon exemple de base pour analyser XML dans python en utilisant Element Tree. De ce que je peux trouver, il semble que ce soit la bibliothèque la plus facile à utiliser pour l'analyse XML Voici un exemple de XML avec lequel je travaille:

<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>

Je suis capable de faire ce dont j'ai besoin, en utilisant une méthode codée en dur. Mais j'ai besoin que mon code soit un peu plus dynamique. Voici ce qui a fonctionné:

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

Voici quelques solutions que j'ai essayées, mais aucune d'entre elles n'a fonctionné, indiquant qu'elles ne pouvaient pas trouver timeSeries (ou autre chose que j'ai essayée):

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

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

Fondamentalement, je veux charger le fichier XML, rechercher la balise timeSeries et parcourir les balises value en renvoyant le dateTime et la valeur de la balise elle-même; tout ce que je fais dans l'exemple ci-dessus, mais sans coder en dur les sections de xml qui m'intéressent. Quelqu'un peut-il m'indiquer des exemples ou me faire des suggestions sur la façon de procéder?


Merci pour votre aide. En utilisant les deux suggestions ci-dessous, vous avez travaillé sur le fichier exemple que j'ai fourni. Cependant, elles ne fonctionnaient pas sur le fichier complet. Voici l'erreur que je reçois du fichier réel lorsque j'utilise la méthode d'Ed Carrel:

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

J'ai pensé qu'il y avait quelque chose dans le vrai fichier qu'il n'aimait pas, alors j'ai progressivement supprimé les choses jusqu'à ce que cela fonctionne. Voici les lignes que j'ai changées:

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>

Supprimer les attributs qui ont 'xsi: ...' corrige le problème. Le 'xsi: ...' n'est-il pas valide XML? Il sera difficile pour moi de les supprimer par programmation. Des suggestions de solutions?

Voici le fichier XML complet: http://www.sendspace.com/file/lofcpt


Lorsque j'ai initialement posé cette question, je ne connaissais pas les espaces de noms en XML. Maintenant que je sais ce qui se passe, je n'ai plus besoin de supprimer les attributs "xsi", qui sont les déclarations d'espace de noms. Je viens de les inclure dans mes recherches xpath. Voir cette page pour plus d’informations sur les espaces de noms en lxml.

62
Casey

Donc, j'ai ElementTree 1.2.6 sur ma boîte maintenant, et ai exécuté le code suivant contre le morceau XML que vous avez posté:

import elementtree.ElementTree as ET

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

print thingy.attrib

et a obtenu le retour suivant:

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

Il semble avoir trouvé l'élément timeSeries sans avoir besoin d'utiliser d'index numérique.

Ce qui serait utile maintenant, c’est de savoir ce que vous voulez dire lorsque vous dites "cela ne fonctionne pas". Comme cela fonctionne pour moi avec la même entrée, il est peu probable qu'ElementTree soit cassé de manière évidente. Mettez à jour votre question avec des messages d'erreur, des traces, ou tout ce que vous pouvez fournir pour nous aider à vous aider.

46
Ed Carrel

Si j'ai bien compris votre question:

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

ou si vous préférez (et s'il n'y a qu'une seule occurrence de timeSeries/values:

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

La méthode findall() renvoie une liste de tous les éléments correspondants, alors que find() ne renvoie que le premier élément correspondant. Le premier exemple boucle sur tous les éléments trouvés, le second boucle sur les éléments enfants de l'élément values, aboutissant dans ce cas au même résultat.

Cependant, je ne vois pas d'où vient le problème de ne pas trouver timeSeries. Peut-être avez-vous juste oublié l'appel getroot()? (notez que vous n'en avez pas vraiment besoin, car vous pouvez également utiliser l'élément elemente, si vous modifiez l'expression du chemin, par exemple, /timeSeriesResponse/timeSeries/values ou //timeSeries/values)

21
Steven