2015-09-10 7 views
6

Desidero trattare i dati dal file .tcx (modulo xml) tra tag specifici con Python.
Il formato del file è come indicato di seguito.Come acquisire le serie di dati dai file xml o tcx

<Track> 
     <Trackpoint> 
     <Time>2015-08-29T22:04:39.000Z</Time> 
     <Position> 
      <LatitudeDegrees>37.198049426078796</LatitudeDegrees> 
      <LongitudeDegrees>127.07204628735781</LongitudeDegrees> 
     </Position> 
     <AltitudeMeters>34.79999923706055</AltitudeMeters> 
     <DistanceMeters>7.309999942779541</DistanceMeters> 
     <HeartRateBpm> 
      <Value>102</Value> 
     </HeartRateBpm> 
     <Cadence>76</Cadence> 
     <Extensions> 
      <TPX xmlns="http://www.garmin.com/xmlschemas/ActivityExtension/v2"> 
      <Watts>112</Watts> 
      </TPX> 
     </Extensions> 
     </Trackpoint> 
....Lots of <Trackpoint> ... </Trackpoint> 
</Track> 

Alla fine, farò tabella di dati con le colonne di 'Lattitude, Altitude, ... Watts'.
Per prima cosa ho provato a creare un elenco di dati con caratteri tatti (come Watts .../Watts) con BeautifulSoup, xpath, ecc. Ma sono un principiante che si occupa di questi strumenti. Come posso prendere i dati tra i tag nel file xml con Python?

risposta

2

È possibile utilizzare il modulo lxml insieme a XPath. lxml è utile per analizzare il codice XML/HTML, attraversare gli alberi degli elementi e restituire testo/attributi degli elementi. Puoi selezionare particolari elementi, gruppi di elementi o attributi di elementi usando XPath. Utilizzando i dati esempio:

content = ''' 
<Track> 
     <Trackpoint> 
     <Time>2015-08-29T22:04:39.000Z</Time> 
     <Position> 
      <LatitudeDegrees>37.198049426078796</LatitudeDegrees> 
      <LongitudeDegrees>127.07204628735781</LongitudeDegrees> 
     </Position> 
     <AltitudeMeters>34.79999923706055</AltitudeMeters> 
     <DistanceMeters>7.309999942779541</DistanceMeters> 
     <HeartRateBpm> 
      <Value>102</Value> 
     </HeartRateBpm> 
     <Cadence>76</Cadence> 
     <Extensions> 
      <TPX xmlns="http://www.garmin.com/xmlschemas/ActivityExtension/v2"> 
      <Watts>112</Watts> 
      </TPX> 
     </Extensions> 
     </Trackpoint> 
....Lots of <Trackpoint> ... </Trackpoint> 
</Track> 
''' 

from lxml import etree 

tree = etree.XML(content) 
time = tree.xpath('Trackpoint/Time/text()') 

print(time) 

uscita

['2015-08-29T22:04:39.000Z'] 
+0

Grazie per la soluzione semplice. Ho ricevuto gli altri dati tranne il Watts. Forse il tag TPX "xmlns = ..." causa problemi. Puoi testarlo? –

2

È anche possibile utilizzare il modulo lxml per convertire XML in formato CSV (per l'importazione in seguito in un dataframe, foglio di calcolo o tabella di database) utilizzando un iterata Elenco di Python su vari XPath.

Avviso l'ultimo nodo Watts è un XPath speciale, più lungo, che deve sfuggire allo spazio dei nomi speciale, xlmns non registrato nell'XML campione.

import os, csv 
import lxml.etree as ET 

# SET DIRECTORY 
cd = os.path.dirname(os.path.abspath(__file__)) 

# LOAD XML FILE 
xmlfile = 'trackXML.xml' 
dom = ET.parse(os.path.join(cd, xmlfile)) 

# DEFINING COLUMNS 
columns = ['latitude', 'longitude', 'altitude', 'distance', 'watts'] 

# OPEN CSV FILE 
with open(os.path.join(cd,'trackData.csv'), 'w') as m: 
    writer = csv.writer(m)  
    writer.writerow(columns) 

    nodexpath = dom.xpath('//Trackpoint') 

    dataline = [] # FOR ONE-ROW CSV APPENDS 
    datalines = [] # FOR FINAL OUTPUT 
    for j in range(1,len(nodexpath)+1):   
     dataline = [] 

     # LOCATE PATH OF EACH NODE VALUE 
     latitudexpath = dom.xpath('//Trackpoint[{0}]/Position/LatitudeDegrees/text()'.format(j)) 
     dataline.append('') if latitudexpath == [] else dataline.append(latitudexpath[0]) 

     longitudexpath = dom.xpath('//Trackpoint[{0}]/Position/LongitudeDegrees/text()'.format(j)) 
     dataline.append('') if longitudexpath == [] else dataline.append(longitudexpath[0]) 

     altitudexpath = dom.xpath('//Trackpoint[{0}]/AltitudeMeters/text()'.format(j)) 
     dataline.append('') if altitudexpath == [] else dataline.append(altitudexpath[0]) 

     distancexpath = dom.xpath('//Trackpoint[{0}]/DistanceMeters/text()'.format(j)) 
     dataline.append('') if distancexpath == [] else dataline.append(distancexpath[0]) 

     wattsxpath = dom.xpath("//Trackpoint[{0}]/*[name()='Extensions']/*[name()='TPX']/*[name()='Watts']/text()".format(j)) 
     dataline.append('') if wattsxpath == [] else dataline.append(wattsxpath[0]) 

     datalines.append(dataline) 
     writer.writerow(dataline) 

print(datalines) 

Oltre ai file CSV, sotto è l'uscita elenco datalines di colonne selezionate: programma

[['37.198049426078796', '127.07204628735781', '34.79999923706055', '7.309999942779541', '112']] 
+0

La tua soluzione è quella che voglio! Ma non funziona. Il messaggio di errore è come questo. File "xml2obj.py", riga 15, in con open (os.path.join (cd, 'trackData.csv'), 'w', newline = '') come m: TypeError: 'newline' è un argomento parola chiave non valido per questa funzione –

+0

Questa è una soluzione Python 3. Probabilmente stai usando Python 2.7 che non accetta 'newline' come argomento nella funzione' open() '. Basta rimuoverlo. Vedi la mia modifica. – Parfait

0

Il pitone https://github.com/cast42/vpower/blob/master/vpower.py itera file TCX specificato nella riga di comando e aggiungere un campo di potenza per tutte le misure dell'attività ciclistica. Usa la libreria lxml per la velocità e perché si occupa di spazi dei nomi. Nelle versioni precedenti di questo programma ho utilizzato xml.etree.ElementTree ma ho incontrato problemi con gli spazi dei nomi.

Problemi correlati