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 для некоторых деталей о .


извинения за использование уже сделанных инструментов здесь, но это сделало работу с вашими данными:

  1. преобразование XML в JSON:http://convertjson.com/xml-to-json.htm
  2. возьмите этот 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 может быть хорошим подходом. Вы многие найдете соответствующие скрипты указал чтобы в этих ссылках.