복붙노트

[PYTHON] 파이썬에서 XML을 CSV로

PYTHON

파이썬에서 XML을 CSV로

파이썬에서 XML 파일을 CSV로 변환하는 데 많은 어려움을 겪고 있습니다. 나는 많은 포럼을 보았고, lxml과 xmlutils.xml2csv를 모두 시도했지만, 제대로 작동하지는 않습니다. Garmin GPS 장치의 GPS 데이터입니다.

여기 내 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 파일을 출력하고 머리글은 위도와 경도를 출력합니다.

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)

어떻게해야합니까? 내가 초보자라는 것을 알기에 더 포괄적 인 설명이 최고로 멋집니다!

해결법

  1. ==============================

    1.이것은 이름 공간이있는 XML 문서입니다. 따라서 각각의 네임 스페이스를 사용하여 노드를 처리해야합니다.

    이것은 이름 공간이있는 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에 매핑되며 와 같은 요소에서 사용됩니다. xmlns 다음에 짧은 형식이없는 마지막 부분을 기본 네임 스페이스라고하며 네임 스페이스를 명시 적으로 사용하지 않는 문서의 모든 요소에 적용되므로 요소에 적용됩니다 게다가.

    따라서 이러한 요소를 선택하려면 root.iter ( '{http://www.topografix.com/GPX/1/1} trkpt')를 작성해야합니다.

    시간과 고도를 얻으려면 trkpt.find ()를 사용하여 trkpt 노드 아래의 이러한 요소에 액세스 한 다음 element.text를 사용하여 요소의 텍스트 내용 (lat 및 lon과 같은 속성과 반대)을 검색 할 수 있습니다. 또한 time 요소와 ele 요소가 기본 네임 스페이스를 사용하기 때문에 {namespace} 요소 구문을 다시 사용하여 해당 노드를 선택해야합니다.

    그래서 다음과 같이 사용할 수 있습니다.

    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 네임 스페이스에 대한 Wikipedia 기사를 참조하십시오. 또한 .gpx 형식에 대한 자세한 내용은 GPS eXchange Format을 참조하십시오.

  2. ==============================

    2.이미 제작 된 도구를 사용하는 것에 대해 사과드립니다. 그러나 이것이 귀하의 데이터로 이루어졌습니다.

    이미 제작 된 도구를 사용하는 것에 대해 사과드립니다. 그러나 이것이 귀하의 데이터로 이루어졌습니다.

    그것은 당신의 데이터와 함께 매력처럼 일했습니다.

    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가 좋은 접근 방법이라고 생각합니다. 당신은 그 링크에서 지적 된 관련 스크립트를 많이 찾습니다.

  3. from https://stackoverflow.com/questions/20714038/xml-to-csv-in-python by cc-by-sa and MIT license