PythonでGPXファイルの値を取得する


GPXファイルは、Garmin社製のGPSデバイスやEPSONのGPSリストウォッチに採用されている位置情報を取り扱うためのファイル形式の1種です。XML形式のテキストなので頑張ればそのまま目で読めないこともないですが、プログラム的に扱うなら何かしらの別の形式になっていたほうが便利です。

PythonのSAXモジュールを使ってGPXファイルの中身を読み取ってみます。

GPXファイルはいくつか種類があるのですが、代表的な2つ、トラックポイント形式とウェイポイント形式を読み出してみます。

```python:parser.py
import xml
from xml.sax.handler import ContentHandler


class WayPointHandler(ContentHandler):
    """ウェイポイント形式のハンドラ
    """

    def __init__(self, buf):
        self.buf = buf

        self.results = []
        self.lon = None
        self.lat = None
        self.ele = None
        self.inEle = False

    def startElement(self, name, attrs):
        if name == 'wpt':  # wptエレメントだったらlon, latを取得
            self.ele = None
            self.lon = attrs['lon']
            self.lat = attrs['lat']
        elif name == 'ele':  # eleエレメントだったらフラグを立てる
            self.inEle = True

    def endElement(self, name):
        # 配列に追加してフラグを初期化
        if name == 'wpt':
            self.results.append([self.lon, self.lat, self.ele])
        elif name == 'ele':
            self.inEle = False

    def characters(self, content):
        if self.inEle:  # エレメント内の文字列を取得する
            self.ele = content.strip()

    def parse(self):
        """指定されたファイルの緯度経度および標高を返す。

        @return: [[longitude, latitude, altitude], ... ]
        @rtype: list
        """
        parser = xml.sax.make_parser()
        parser.setContentHandler(self)
        parser.parse(self.buf)

        return self.results


class TrackPointHandler(ContentHandler):
    """トラックポイント形式GPXのハンドラ
    """

    def __init__(self, buf):
        self.buf = buf

        self.results = []
        self.lon = None
        self.lat = None
        self.ele = None
        self.inEle = False

    def startElement(self, name, attrs):
        if name == 'trkpt':  # trkptエレメントだったらlon, latを取得
            self.ele = None
            self.lon = attrs['lon']
            self.lat = attrs['lat']
        elif name == 'ele':  # eleエレメントだったらフラグを立てる
            self.inEle = True

    def endElement(self, name):
        # 取得した値を配列に追加、フラグを初期化
        if name == 'trkpt':
            self.results.append([self.lon, self.lat, self.ele])
        elif name == 'ele':
            self.inEle = False

    def characters(self, content):
        if self.inEle:  # フラグが立っていたらエレメント内の文字列を取得する
            self.ele = content.strip()

    def parse(self):
        """指定されたファイルの緯度経度および標高を返す。

        @return: [[longitude, latitude, altitude], ... ]
        @rtype: list
        """
        parser = xml.sax.make_parser()
        parser.setContentHandler(self)
        parser.parse(self.buf)

        return self.results
```

使い方。

ウェイポイント形式のGPXファイルは[Yahoo! Japanルートラボ](http://latlonglab.yahoo.co.jp/route/)辺りから拾ってきてください。

```python
>>> f = open('waypoints.gpx', 'rt')
>>> handler = parser.WayPointHandler(f)
>>> handler.parse()
[[u'141.6223275', u'39.0208238888889', u'4.8'],
 [u'141.622242777778', u'39.0208955555556', u'4.9'],
 [u'141.62209', u'39.0210269444444', u'5.5']]
 ...
```

トラックポイント形式のファイルはサンプルが見当たらなかったので適当にググって拾ってきてください(汗

```python
>>> f = open('trackponits.gpx', 'rt')
>>> handler = parser.TrackPointHandler(f)
>>> handler.parse()
[[u'141.622163611111', u'39.0209638888889', u'4.9'],
 [u'141.622242777778', u'39.0208955555556', u'4.9'],
 [u'141.6223275', u'39.0208238888889', u'4.8'],
 [u'141.623074722222', u'39.0201783333333', u'4.4'],
 ...
```



# あわせて読みたい

* [XcodeでiOSデバイスの位置情報をシミュレートする](http://qiita.com/key/items/d33aba1f7eb76f898730)