Читать GPX, используя Python ElementTree.register_namespace?

Я уже некоторое время бьюсь головой о стену. Согласно документации, это должно быть простым. Все, что я хочу сделать, это прочитать файл GPX. Однако файлы GPX свободно используют пространства имен, что теоретически имеет смысл. Однако я не могу заставить ElementTree их прочитать. Вот код, который я пытаюсь использовать...

def loadGpx(self, sourceFile):
    ElementTree.register_namespace('gpx', 'http://www.topografix.com/GPX/1/1')
    eTree = ElementTree.ElementTree()
    eTree.parse(sourceFile)

    print eTree.findall('wpt')

Чтобы вытащить путевые точки из файла GPX, как это...

<?xml version="1.0" encoding="utf-8"?>
<gpx creator="Garmin Desktop App" version="1.1" 
    xsi:schemaLocation="http://www.topografix.com/GPX/1/1 
                    http://www.topografix.com/GPX/1/1/gpx.xsd 
                    http://www.garmin.com/xmlschemas/WaypointExtension/v1 
                    http://www8.garmin.com/xmlschemas/WaypointExtensionv1.xsd 
                    http://www.garmin.com/xmlschemas/TrackPointExtension/v1 
                    http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd 
                    http://www.garmin.com/xmlschemas/GpxExtensions/v3 
                    http://www8.garmin.com/xmlschemas/GpxExtensionsv3.xsd 
                    http://www.garmin.com/xmlschemas/ActivityExtension/v1 
                    http://www8.garmin.com/xmlschemas/ActivityExtensionv1.xsd 
                    http://www.garmin.com/xmlschemas/AdventuresExtensions/v1 
                    http://www8.garmin.com/xmlschemas/AdventuresExtensionv1.xsd" 
    xmlns="http://www.topografix.com/GPX/1/1" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:wptx1="http://www.garmin.com/xmlschemas/WaypointExtension/v1" 
    xmlns:gpxtrx="http://www.garmin.com/xmlschemas/GpxExtensions/v3" 
    xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" 
    xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3" 
    xmlns:abp="http://www.garmin.com/xmlschemas/ActivityExtension/v1" 
    xmlns:adv="http://www.garmin.com/xmlschemas/AdventuresExtensions/v1">

    <metadata>
        <link href="http://www.garmin.com">
          <text>Garmin International</text>
        </link>
        <time>2012-01-17T03:21:12Z</time>
        <bounds maxlat="45.708811283111572" maxlon="-121.3884991966188" 
                minlat="45.407062936574221" minlon="-121.54939779080451" />
    </metadata>

  <wpt lat="45.708682453259826" lon="-121.51224257424474">
    <time>2012-01-06T19:00:02Z</time>
    <name>1-State and First, start MHL</name>
    <sym>Bike Trail</sym>
    <extensions>
      <gpxx:WaypointExtension>
        <gpxx:DisplayMode>SymbolAndName</gpxx:DisplayMode>
      </gpxx:WaypointExtension>
    </extensions>
  </wpt>

  <wpt lat="45.615267734974623" lon="-121.43857721239328">
    <time>2012-01-07T15:38:14Z</time>
    <name>10-Right at fork staying on Huskey Rd</name>
    <sym>Bike Trail</sym>
    <extensions>
      <gpxx:WaypointExtension>
        <gpxx:DisplayMode>SymbolAndName</gpxx:DisplayMode>
      </gpxx:WaypointExtension>
    </extensions>
  </wpt>

Правда, это займет больше, чем просто print eTree.findall('wpt'), но если я смогу зайти так далеко, я раньше работал с xml. Эта часть проста. Однако эта штука с пространством имен сводит меня с ума.

Я благодарю вас заранее. Это сводит меня с ума.


person knu2xs    schedule 06.08.2013    source источник


Ответы (2)


register_namespace() управляет используемыми префиксами. при сериализации XML, но это не влияет на синтаксический анализ.

С ElementTree сделайте это так:

from xml.etree import ElementTree as ET

tree = ET.parse("gpx.xml")
for elem in tree.findall("{http://www.topografix.com/GPX/1/1}wpt"):
    print elem

Результирующий вывод:

<Element '{http://www.topografix.com/GPX/1/1}wpt' at 0x201c550>
<Element '{http://www.topografix.com/GPX/1/1}wpt' at 0x201c730>

С lxml вы также можете использовать это:

from lxml import etree

NSMAP = {"gpx": "http://www.topografix.com/GPX/1/1"}

tree = etree.parse("gpx.xml")
for elem in tree.findall("gpx:wpt", namespaces=NSMAP):
    print elem
person mzjn    schedule 06.08.2013
comment
Это чрезвычайно полезно, разъяснение того, что на самом деле делает register_namespace(). Сериализация, если я правильно понимаю, полезна только при создании вывода. Для того, что я делаю, кажется, что модуль парсера gpxpy действительно может быть хорошей отправной точкой. Тем не менее, спасибо за помощь в разъяснении этого. Опять же, Stackoverflow показывает мне, как мне нужно действовать! - person knu2xs; 06.08.2013

Почему бы вам просто не использовать существующую библиотеку GPX?

бессовестный плагин: с gpxpy https://github.com/tkrajina/gpxpy парсинг путевых точек из вашего файла работает отлично :

import gpxpy

gpx_sample = """...your GPX sample here..."""

gpx = gpxpy.parse(gpx_sample)

for wpt in gpx.waypoints:
    print wpt.latitude, wpt.longitude

Даже если вы не хотите использовать библиотеку, вы можете просто проверить код, чтобы увидеть, как он анализирует файл XML.

person puzz    schedule 06.08.2013
comment
Да, это бесстыдная вилка и справедливый вопрос. Во-первых, я хочу понять, как это использовать, потому что это применимо к другому проекту, над которым я работаю. Большую часть времени это делается ради обучения. Вы использовали minidom, а я хотел бы использовать ElementTree, так как я понимаю, как с ним работать... при условии, что я смогу преодолеть этот горб. Во-вторых, мне не нужно все в gpxpy. В конечном итоге он будет подключен к ArcGIS, поэтому у меня есть все, что мне нужно для анализа, и даже больше. В результате все, что мне нужно, это умение читать эти теги. - person knu2xs; 06.08.2013
comment
Кстати, я использую minidom, только lxml недоступен (поскольку lxml намного быстрее, чем minidom). - person puzz; 06.08.2013