package mlgpx
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 ()
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
On This Page