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.
The mlgpx CLI provides tools for manipulating GPX files from the command line.
# Install from source
dune build @install
dune install
# Or use opam
opam install mlgpx# 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# Basic file information
mlgpx info file.gpx
# Detailed analysis with waypoint details
mlgpx info --verbose file.gpx# General help
mlgpx --help
# Command-specific help
mlgpx convert --help
mlgpx info --helpThe library is split into four main components:
gpx)js_of_ocamlgpx_unix)result typesgpx_eio)mlgpx)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 suitetype 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) resulttype extension = {
namespace : string option;
name : string;
attributes : (string * string) list;
content : extension_content;
}(* 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(* 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(* 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 -> tracktype validation_result = {
issues : validation_issue list;
is_valid : bool;
}
val Gpx_validate.validate_gpx : gpx -> validation_result
val Gpx_validate.is_valid : gpx -> boolThe 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 stringAll operations return ('a, error) result for 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)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 ()