Skip to content

GPX Import #89

@bkeepers

Description

@bkeepers

Import any valid GPX file and create the appropriate entities — markers from <wpt>, tracks from <trk>, and routes from <rte>. A single GPX file can contain any combination of these, so one import may create multiple entities.

Parsing (lib/importGPX.ts)

Use fast-xml-parser XMLParser (the inverse of the existing XMLBuilder used for export) to parse GPX XML into a JS object, then map elements to database inserts.

type ImportResult = {
  markers: Marker[];
  tracks: Track[];
  routes: Route[];
};

async function importGPX(xml: string): Promise<ImportResult>;

Element Mapping

<wpt> → Marker:

latitude  ← wpt@lat
longitude ← wpt@lon
name      ← wpt/name
notes     ← wpt/desc
icon      ← wpt/sym (map to nearest AnnotationIcon, or null)

<trk> → Track + TrackPoints:

name       ← trk/name
started_at ← first trkpt/time
ended_at   ← last trkpt/time
distance   ← computed from point-to-point distances

Per trkpt:
  latitude  ← trkpt@lat
  longitude ← trkpt@lon
  timestamp ← trkpt/time
  speed     ← trkpt/extensions/speed
  heading   ← trkpt/extensions/course

Multiple <trkseg> within a single <trk> are concatenated into one track.

<rte> → Route + RoutePoints:

name ← rte/name

Per rtept:
  latitude  ← rtept@lat
  longitude ← rtept@lon
  name      ← rtept/name
  position  ← index order in file

Entry Points

1. Share sheet / "Open with"

Register SeaScape as a handler for .gpx files (UTI: com.topografix.gpx, MIME: application/gpx+xml) via iOS document types config in app.json. When a user shares a GPX file to SeaScape or opens one from Files, the app receives the file URI.

2. Import button in MainSheet

Add an "Import GPX" option that opens the system file picker (expo-document-picker) filtered to .gpx files.

Import Flow

  1. Read file contents (from share URI or document picker)
  2. Parse XML via fast-xml-parser
  3. Validate: check for <gpx> root element, bail with user-friendly error if invalid
  4. Process all <wpt>, <trk>, and <rte> elements in a single DB transaction
  5. Show summary: "Imported 3 markers, 1 track, 2 routes"
  6. Navigate to the first imported entity (or route list if multiple routes)

Error Handling

  • Invalid XML → "This file doesn't appear to be a valid GPX file"
  • Missing required fields (lat/lon) → skip that element, include in summary ("1 waypoint skipped — missing coordinates")
  • Empty file (no elements) → "No waypoints, tracks, or routes found in this file"

New Files

File Purpose
lib/importGPX.ts GPX parser — creates markers, tracks, and routes

Modified Files

File Change
app.json Register GPX file type handler (UTI: com.topografix.gpx)
app/MainSheet.tsx Add "Import GPX" button

Implementation Order

  1. GPX parserlib/importGPX.ts with pure parsing logic + comprehensive tests
  2. Import UI — File picker in MainSheet via expo-document-picker
  3. File type registrationapp.json config for "Open with" / share sheet handling

Testing

Pure parsing logic with no React dependencies — test with sample GPX files:

  • File with only <wpt> elements
  • File with only <trk> elements (single and multi-segment)
  • File with only <rte> elements
  • File with a mix of all three
  • Real-world GPX files from common apps (Navionics, OpenCPN, etc.)
  • Malformed / missing fields
  • Round-trip: export then import, verify data matches

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions