2009-11-23 7 views
55

J'ai du mal à trouver un bon exemple de base pour analyser XML en python à l'aide d'Element Tree. D'après ce que je peux trouver, cela semble être la bibliothèque la plus facile à utiliser pour analyser XML. Voici un exemple de XML Je travaille avec:Analyse XML en Python à l'aide de l'exemple 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> 

Je suis capable de faire ce que je dois, 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 choses que j'ai essayé, aucun d'entre eux travaillaient, les rapports qu'ils ne pouvaient pas trouver TimeSeries (ou toute autre chose que j'ai essayé):

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 de valeur, en retournant le dateTime et la valeur de la balise elle-même; tout ce que je fais dans l'exemple ci-dessus, mais pas de coder les sections de xml qui m'intéressent. Est-ce que quelqu'un peut me donner des exemples, ou me donner quelques suggestions sur la façon de travailler?


Merci pour toute l'aide. En utilisant les deux suggestions ci-dessous a travaillé sur le fichier d'exemple que j'ai fourni, cependant, ils n'ont pas travaillé sur le fichier complet. Voici l'erreur que je reçois du fichier réel lorsque j'utilise la méthode de Ed Carrel:

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

je me suis dit il y avait quelque chose dans le fichier réel, il n'a pas aimé, donc j'enlevé les choses incremently jusqu'à ce qu'il a travaillé. Voici les lignes que je changé:

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> 

Suppression des attributs qui ont « xsi: ... » résolu le problème. Le 'xsi: ...' n'est-il pas valide? Il sera difficile pour moi de les supprimer par programme. Avez-vous des suggestions de travail?

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


Quand j'ai demandé à l'origine de cette question, je ne connaissais pas de XML dans les espaces de noms. Maintenant que je sais ce qui se passe, je n'ai pas besoin de supprimer les attributs "xsi", qui sont les déclarations d'espace de noms. Je les inclus simplement dans mes recherches xpath. Voir this page pour plus d'informations sur les espaces de noms dans lxml.

+0

Je pourrais vous suggérer de consulter le module 'etree' fourni par' lxml'? Je l'ai découvert récemment et je l'ai trouvé largement supérieur à ElementTree. Il a été écrit comme un remplacement qui émule complètement ElementTree. – jathanism

+0

J'ai fini par utiliser lxml, car c'était un peu plus facile de travailler avec, mais j'ai toujours le problème décrit ci-dessus. Pour une solution de contournement, je scanne au préalable le fichier xml et supprime toutes les instances de "xsi: type". Les méthodes décrites dans les réponses ci-dessous fonctionnent bien. – Casey

Répondre

40

J'ai donc ElementTree 1.2.6 sur ma boîte maintenant, et a couru 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 suivant retour:

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

Il apparaît avoir trouvé l'élément timeSeries sans avoir besoin d'utiliser des indices numériques.

Ce qui serait utile maintenant, c'est de savoir ce que vous voulez dire quand vous dites «ça ne marche pas». Comme cela fonctionne pour moi avec la même contribution, il est peu probable que ElementTree soit brisé de façon évidente. Mettez à jour votre question avec les messages d'erreur, les backtraces ou tout ce que vous pouvez fournir pour nous aider à vous aider.

+28

Pour les nouvelles versions de python, l'importation a été modifiée en: import xml.etree.ElementTree comme ET – Louis

+0

@Louis: que voulez-vous dire par 'les nouvelles versions de python'? –

+0

@Monica Heddneck: Comme ce commentaire a plus de six ans, je devrais dire chaque python au-dessus de 2,3 ... – Louis

18

Si je comprends bien 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() retourne une liste de tous les éléments correspondant à , alors que find() renvoie uniquement le premier élément correspondant: le premier exemple boucle sur tous les éléments trouvés, les secondes boucles sur les éléments enfants de l'élément values, dans ce cas conduisant à la même résultat.

Je ne vois pas où le problème de ne pas trouver timeSeries vient cependant. Peut-être que vous venez d'oublier l'appel getroot()? (notez que vous n'en avez pas vraiment besoin car vous pouvez aussi travailler avec l'élément elementtre, par exemple /timeSeriesResponse/timeSeries/values ou //timeSeries/values)

+0

Cela fonctionne très bien. Je l'ai utilisé avec le module 'from lxml import etree'. 'doc = etree.parse ('test.xml')' –