XML в CSV в Python
у меня много проблем с преобразованием XML-файла в CSV в Python. Я смотрел на многих форумах, пробовал как lxml, так и xmlutils.xml2csv, но я не могу заставить его работать. Это данные GPS с GPS-устройства Garmin.
вот как выглядит мой XML-файл, сокращенный, конечно:
<?xml version="1.0" encoding="utf-8"?>
<gpx xmlns:tc2="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tp1="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" xmlns="http://www.topografix.com/GPX/1/1" version="1.1" creator="TC2 to GPX11 XSLT stylesheet" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd">
<trk>
<name>2013-12-03T21:08:56Z</name>
<trkseg>
<trkpt lat="45.4852855" lon="-122.6347885">
<ele>0.0000000</ele>
<time>2013-12-03T21:08:56Z</time>
</trkpt>
<trkpt lat="45.4852961" lon="-122.6347926">
<ele>0.0000000</ele>
<time>2013-12-03T21:09:00Z</time>
</trkpt>
<trkpt lat="45.4852982" lon="-122.6347897">
<ele>0.2000000</ele>
<time>2013-12-03T21:09:01Z</time>
</trkpt>
</trkseg>
</trk>
</gpx>
в моем массивном XML-файле есть несколько тегов trk, но я могу отделить их-они представляют собой разные "сегменты" или поездки на устройстве GPS. Все, что я хочу, это файл CSV что-то вроде этого:
LAT LON TIME ELE
45.4... -122.6... 2013-12... 0.00...
... ... ... ...
вот код у меня есть до сих пор:
## Call libraries
import csv
from xmlutils.xml2csv import xml2csv
inputs = "myfile.xml"
output = "myfile.csv"
converter = xml2csv(inputs, output)
converter.convert(tag="WHATEVER_GOES_HERE_RENDERS_EMPTY_CSV")
это еще один альтернативный код. Он просто выводит CSV-файл без данных, только заголовки lat
и lon
.
import csv
import lxml.etree
x = '''
<?xml version="1.0" encoding="utf-8"?>
<gpx xmlns:tc2="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tp1="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" xmlns="http://www.topografix.com/GPX/1/1" version="1.1" creator="TC2 to GPX11 XSLT stylesheet" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd">
<trk>
<name>2013-12-03T21:08:56Z</name>
<trkseg>
<trkpt lat="45.4852855" lon="-122.6347885">
<ele>0.0000000</ele>
<time>2013-12-03T21:08:56Z</time>
</trkpt>
<trkpt lat="45.4852961" lon="-122.6347926">
<ele>0.0000000</ele>
<time>2013-12-03T21:09:00Z</time>
</trkpt>
<trkpt lat="45.4852982" lon="-122.6347897">
<ele>0.2000000</ele>
<time>2013-12-03T21:09:01Z</time>
</trkpt>
</trkseg>
</trk>
</gpx>
'''
with open('output.csv', 'w') as f:
writer = csv.writer(f)
writer.writerow(('lat', 'lon'))
root = lxml.etree.fromstring(x)
for trkpt in root.iter('trkpt'):
row = trkpt.get('lat'), trkpt.get('lon')
writer.writerow(row)
как мне это сделать? Пожалуйста, поймите, что я новичок, поэтому более полное объяснение было бы супер удивительным!
2 ответов
это в пространстве имен XML-документа. Поэтому вам нужно обратиться к узлам, используя их соответствующие пространства имен.
пространства имен, используемые в документе определены вверху:
xmlns:tc2="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tp1="http://www.garmin.com/xmlschemas/TrackPointExtension/v1"
xmlns="http://www.topografix.com/GPX/1/1"
таким образом, первое пространство имен сопоставляется с короткой формой tc2
и будет использоваться в элемент типа <tc2:foobar/>
. Последний, который не имеет короткой формы после xmlns
, называется пространство имен по умолчанию и это относится ко всем элементы в документе, которые явно не используют пространство имен - поэтому оно применяется к вашему <trkpt />
элементы.
поэтому вам нужно будет написать root.iter('{http://www.topografix.com/GPX/1/1}trkpt')
для выбора этих элементов.
для того, чтобы узнать время и высоту, вы можете использовать trkpt.find()
для доступа к этим элементам ниже trkpt
узел, а затем element.text
чтобы получить текстовое содержимое этих элементов (в отличие от атрибутов, таких как lat
и lon
). Кроме того, потому что time
и ele
элементы также используют пространство имен по умолчанию, которое необходимо использовать {namespace}element
синтаксис снова, чтобы выбрать эти узлы.
таким образом, вы можете использовать что-то вроде этого:
NS = 'http://www.topografix.com/GPX/1/1'
header = ('lat', 'lon', 'ele', 'time')
with open('output.csv', 'w') as f:
writer = csv.writer(f)
writer.writerow(header)
root = lxml.etree.fromstring(x)
for trkpt in root.iter('{%s}trkpt' % NS):
lat = trkpt.get('lat')
lon = trkpt.get('lon')
ele = trkpt.find('{%s}ele' % NS).text
time = trkpt.find('{%s}time' % NS).text
row = lat, lon, ele, time
writer.writerow(row)
дополнительные сведения о пространствах имен XML см. В раздел пространства имен в учебнике lxml и статья Википедии о пространствах имен XML. Также смотрите формат обмена GPS для некоторых деталей о .
извинения за использование уже сделанных инструментов здесь, но это сделало работу с вашими данными:
- преобразование XML в JSON:http://convertjson.com/xml-to-json.htm
- возьмите этот JSON и преобразуйте JSON в CSV:https://konklone.io/json/
Он работал как шарм с вашими данными.
ele,time,_lat,_lon
0.0000000,2013-12-03T21:08:56Z,45.4852855,-122.6347885
0.0000000,2013-12-03T21:09:00Z,45.4852961,-122.6347926
0.2000000,2013-12-03T21:09:01Z,45.4852982,-122.6347897
поэтому для кодирования я считаю, что XML > JSON > CSV может быть хорошим подходом. Вы многие найдете соответствующие скрипты указал чтобы в этих ссылках.