package mlgpx

  1. Overview
  2. Docs
Library and CLI for parsing and generating GPS Exchange (GPX) formats

Install

dune-project
 Dependency

Authors

Maintainers

Sources

mlgpx-1.0.0.tbz
md5=5342bb7e601273245a9fe263e5a08770
sha512=cd73b16e988b3ed3cc427a6c6c6d6c9c745adb1eb7efaae3c34e8d006e9c03d9f9d2616cd4118564bd9873903969d3e4053b585e79dbd3e3e7d0f541e2faac83

Description

mlgpx is a streaming GPX (GPS Exchange Format) library for OCaml. It provides a portable core library using the xmlm streaming XML parser, with a separate Unix layer for file I/O operations. The library supports the complete GPX 1.1 specification including waypoints, routes, tracks, and metadata with strong type safety and validation.

Published: 14 Aug 2025

README

mlgpx - an OCaml GPS Exchange Format (GPX) Library

An OCaml library for parsing and generating GPX (GPS Exchange Format) 1.0 and 1.1 files, and a CLI for common manipulation and query options.

Command Line Usage

The mlgpx CLI provides tools for manipulating GPX files from the command line.

Installation

# Install from source
dune build @install
dune install

# Or use opam
opam install mlgpx

Convert Waypoints to Track

# Basic conversion
mlgpx convert waypoints.gpx track.gpx

# With custom track name
mlgpx convert --name "My Route" waypoints.gpx route.gpx

# Sort waypoints by timestamp before conversion
mlgpx convert --sort-time waypoints.gpx sorted_track.gpx

# Sort by name and preserve original waypoints
mlgpx convert --sort-name --preserve waypoints.gpx mixed.gpx

# Verbose output with description
mlgpx convert --verbose --desc "Generated route" waypoints.gpx track.gpx

File Analysis

# Basic file information
mlgpx info file.gpx

# Detailed analysis with waypoint details
mlgpx info --verbose file.gpx

Help

# General help
mlgpx --help

# Command-specific help
mlgpx convert --help
mlgpx info --help

Architecture Overview

The library is split into four main components:

Core Library (gpx)

  • Portable: No Unix dependencies, works with js_of_ocaml
  • Streaming: Uses xmlm for memory-efficient XML processing
  • Type-safe: Strong typing with validation for coordinates and GPS data
  • Pure functional: No side effects in the core parsing/writing logic

Unix Layer (gpx_unix)

  • File I/O: Convenient functions for reading/writing GPX files
  • Result-based: Explicit error handling with result types
  • Validation: Built-in validation with detailed error reporting
  • Utilities: Helper functions for common GPX operations

Effects-Style Layer (gpx_eio)

  • Exception-based: Simplified error handling with exceptions
  • Effects-style API: Similar to Eio patterns but using standard Unix I/O
  • Resource-safe: Automatic file handle management
  • High-level: Convenient functions for common operations

Command Line Interface (mlgpx)

  • Unix-style CLI: Built with cmdliner for proper argument parsing
  • Eio-powered: Uses Eio backend for efficient I/O operations
  • Waypoint conversion: Convert waypoints to tracksets with sorting options
  • File analysis: Inspect GPX files with detailed information display

Key Features

  • Complete GPX 1.0/1.1 support: Waypoints, routes, tracks, metadata, extensions
  • Streaming parser/writer: Memory-efficient for large files
  • Strong type safety: Validated coordinates, GPS fix types, etc.
  • Comprehensive validation: Detailed error and warning reporting
  • Extension support: Handle custom XML elements
  • Cross-platform: Core library has no Unix dependencies

Module Structure

mlgpx/
├── lib/
│   ├── gpx/                # Portable core library
│   │   ├── types.ml        # Type definitions with smart constructors
│   │   ├── parser.ml       # Streaming XML parser
│   │   ├── writer.ml       # Streaming XML writer
│   │   ├── validate.ml     # Validation and error checking
│   │   └── gpx.ml[i]       # Main interface with direct access to all types
│   ├── gpx_unix/           # Unix I/O layer (result-based)
│   │   ├── gpx_io.ml       # File operations with error handling
│   │   └── gpx_unix.ml     # High-level convenience API
│   └── gpx_eio/            # Effects-style layer (exception-based)
│       ├── gpx_io.ml       # File operations with exceptions
│       └── gpx_eio.ml      # High-level effects-style API
├── examples/               # Usage examples
└── test/                   # Test suite

Type System Design

Validated Coordinates

type latitude = private float   (* -90.0 to 90.0 *)
type longitude = private float  (* -180.0 to < 180.0 *)
type degrees = private float    (* 0.0 to < 360.0 *)

(* Smart constructors with validation *)
val latitude : float -> (latitude, string) result
val longitude : float -> (longitude, string) result

GPX Elements

  • Waypoint: Standalone geographic point with metadata
  • Route: Ordered list of waypoints representing a planned path
  • Track: Recorded path consisting of track segments with track points
  • Metadata: Document-level information (bounds, author, etc.)

Extension System

type extension = {
  namespace : string option;
  name : string;
  attributes : (string * string) list;
  content : extension_content;
}

API Design

Streaming Operations

(* Core streaming API *)
val Gpx_parser.parse : Xmlm.input -> gpx result
val Gpx_writer.write : Xmlm.output -> gpx -> unit result

(* String convenience functions *)
val Gpx_parser.parse_string : string -> gpx result  
val Gpx_writer.write_string : gpx -> string result

File Operations (Result-based)

(* Simple file I/O *)
val Gpx_unix.read : string -> gpx result
val Gpx_unix.write : string -> gpx -> unit result

(* With validation *)
val Gpx_unix.read_validated : string -> gpx result
val Gpx_unix.write_validated : string -> gpx -> unit result

(* With backup *)
val Gpx_unix.write_with_backup : string -> gpx -> string result

Effects-Style Operations (Exception-based)

(* Simple file I/O *)
val Gpx_eio.read : unit -> string -> gpx
val Gpx_eio.write : unit -> string -> gpx -> unit

(* With validation *)
val Gpx_eio.read_validated : unit -> string -> gpx
val Gpx_eio.write_validated : unit -> string -> gpx -> unit

(* With backup *)
val Gpx_eio.write_with_backup : unit -> string -> gpx -> string

(* Utility functions *)
val Gpx_eio.make_waypoint : unit -> lat:float -> lon:float -> ?name:string -> unit -> waypoint_data
val Gpx_eio.make_track_from_coords : unit -> name:string -> (float * float) list -> track

Validation

type validation_result = {
  issues : validation_issue list;
  is_valid : bool;
}

val Gpx_validate.validate_gpx : gpx -> validation_result
val Gpx_validate.is_valid : gpx -> bool

Error Handling Strategy

The library uses a comprehensive error type:

type error =
  | Invalid_xml of string
  | Invalid_coordinate of string  
  | Missing_required_attribute of string * string
  | Missing_required_element of string
  | Validation_error of string
  | Xml_error of string
  | IO_error of string

All operations return ('a, error) result for explicit error handling.

Performance Characteristics

  • Memory usage: O(1) for streaming operations, O(n) for complete document
  • Time complexity: O(n) parsing/writing where n = file size
  • Validation: Optional, can be disabled for performance-critical applications
  • Extensions: Parsed lazily, minimal overhead when unused

Usage Examples

Result-based API (Explicit Error Handling)

open Gpx_unix

let create_simple_gpx () =
  (* Create waypoints *)
  let* waypoint = make_waypoint ~lat:37.7749 ~lon:(-122.4194) 
                                ~name:"San Francisco" () in
  
  (* Create track from coordinates *)
  let coords = [(37.7749, -122.4194); (37.7849, -122.4094)] in
  let* track = make_track_from_coords ~name:"Sample Track" coords in
  
  (* Create GPX document *)
  let gpx = Types.make_gpx ~creator:"mlgpx example" in
  let gpx = { gpx with waypoints = [waypoint]; tracks = [track] } in
  
  (* Validate and write *)
  write_validated "output.gpx" gpx

let () = 
  match create_simple_gpx () with
  | Ok () -> Printf.printf "GPX created successfully\n"
  | Error e -> Printf.eprintf "Error: %s\n" (error_to_string e)

Effects-Style API (Exception-based)

open Gpx_eio

let create_simple_gpx () =
  try
    (* Create waypoints *)
    let waypoint = make_waypoint () ~lat:37.7749 ~lon:(-122.4194) 
                                   ~name:"San Francisco" () in
    
    (* Create track from coordinates *)
    let coords = [(37.7749, -122.4194); (37.7849, -122.4094)] in
    let track = make_track_from_coords () ~name:"Sample Track" coords in
    
    (* Create GPX document *)
    let gpx = Gpx.make_gpx ~creator:"mlgpx example" in
    let gpx = { gpx with waypoints = [waypoint]; tracks = [track] } in
    
    (* Validate and write *)
    write_validated () "output.gpx" gpx;
    Printf.printf "GPX created successfully\n"
    
  with
  | Gpx.Gpx_error err ->
      Printf.eprintf "GPX Error: %s\n" (Gpx.error_to_string err)

let () = create_simple_gpx ()

Dev Dependencies (1)

  1. odoc with-doc

Used by

None

Conflicts

None

OCaml

Innovation. Community. Security.