Rust read/write support for GPS Exchange Format (GPX)

Overview

gpx

Crates.io Build Status docs.rs

gpx is a library for reading and writing GPX (GPS Exchange Format) files. It uses the primitives provided by geo-types to allow for storage of GPS data.

Example

extern crate gpx;

use std::io::BufReader;
use std::fs::File;

use gpx::read;
use gpx::{Gpx, Track, TrackSegment};

fn main() {
    // This XML file actually exists — try it for yourself!
    let file = File::open("tests/fixtures/wikipedia_example.gpx").unwrap();
    let reader = BufReader::new(file);

    // read takes any io::Read and gives a Result<Gpx, Error>.
    let gpx: Gpx = read(reader).unwrap();

    // Each GPX file has multiple "tracks", this takes the first one.
    let track: &Track = &gpx.tracks[0];
    assert_eq!(track.name, Some(String::from("Example GPX Document")));

    // Each track will have different segments full of waypoints, where a
    // waypoint contains info like latitude, longitude, and elevation.
    let segment: &TrackSegment = &track.segments[0];

    // This is an example of retrieving the elevation (in meters) at certain points.
    assert_eq!(segment.points[0].elevation, Some(4.46));
    assert_eq!(segment.points[1].elevation, Some(4.94));
    assert_eq!(segment.points[2].elevation, Some(6.87));
}

Current Status

rust-gpx currently supports reading and writing both GPX 1.1 and 1.0. GPX extensions are not yet supported.

Contributing

All contributions are welcome! Please open an issue if you find a bug / have any questions, and pull requests are always appreciated.

License

rust-gpx is licensed under the MIT license.

Comments
  • Switch from RFC3339 to ISO8601 for timestamp encoding

    Switch from RFC3339 to ISO8601 for timestamp encoding

    • [x] I agree to follow the project's code of conduct.
    • [x] I added an entry to CHANGELOG.md if knowledge of this change could be valuable to users.

    Implement changes proposed in https://github.com/georust/gpx/issues/77

    I don't expect this to land directly as it adds a breaking change

    opened by 0b11001111 18
  • Support Number on Tracks

    Support Number on Tracks

    GPX 1.1 Spec includes an optional Number on Track elements, which support is added for here. Some Gpx files exported from google maps appear to include this so included test + test gpx file from that are used to verify change.

    N.b. Number, as a u8, was already present and commented out on the Track struct - in case there was some history there being dragged up (It was already commented out during a refactor 4 years ago and that's as far back as i looked ...)

    • [X] I agree to follow the project's code of conduct.
    • [x] I added an entry to CHANGELOG.md if knowledge of this change could be valuable to users.

    opened by tehsmeely 14
  • Allow empty elevation tags

    Allow empty elevation tags

    Similar to https://github.com/georust/gpx/issues/70, I have a GPX file that has self-closing elevation tags, which of course, contain no value. This appears to be valid per the GPX spec at https://www.topografix.com/GPX/1/1/#type_ptType.

    The GPX file was generated by a Wahoo bike computer.

    This change edits the parsing logic to use a default f64 value of 0.00 for these cases. I didn't see a precedence for handling similar optional values in this lib, so let me know if I should handle this differently in accordance with the project's goals.

    • [x] I agree to follow the project's code of conduct.
    • [x] I added an entry to CHANGELOG.md if knowledge of this change could be valuable to users.

    opened by ebcrowder 12
  • expose `Time`

    expose `Time`

    • [x] I agree to follow the project's code of conduct.
    • [ ] I added an entry to CHANGELOG.md if knowledge of this change could be valuable to users.

    not sure if this is intentionally private, perhaps there is some other way to access time data from waypoints directly as chrono types?

    closes #75 if valid

    opened by nerdypepper 11
  • Support parsing copyright tag in metadata

    Support parsing copyright tag in metadata

    This commit adds the GpxCopyright type and parse/copyright.rs which consumes the tag of the metadata element.

    I've also included a Strava route test case as well as some unit tests in the source file.

    Fixes issue #45

    $ cargo test
    
    test parser::copyright::tests::consume_barebones ... ok
    test parser::copyright::tests::consume_simple_copyright ... ok
    
    test gpx_reader_read_test_strava_route ... ok
    
    opened by pelmers 10
  • Allow empty track name tags

    Allow empty track name tags

    • [x] I agree to follow the project's code of conduct.
    • [x] I added an entry to CHANGELOG.md if knowledge of this change could be valuable to users.

    Fixes #54

    opened by soruh 9
  • Add `xmlns` attribute in written gpx for better garmin compatibility

    Add `xmlns` attribute in written gpx for better garmin compatibility

    I noted that the exported GPX files are not accepted by Garmin software (for example Basecamp), and found out this is due to a missing namespace declaration. This PR adds the necessary xmlns tag to the gpx element.

    • [X] I agree to follow the project's code of conduct.
    • [X] I added an entry to CHANGELOG.md if knowledge of this change could be valuable to users.

    opened by OttoBos 8
  • Do not crash if a gpx file has an extensions tag in its route tag

    Do not crash if a gpx file has an extensions tag in its route tag

    The extensions tag is also allowed in the route tag (see https://www.topografix.com/GPX/1/1/#type_rteType).

    • [x] I agree to follow the project's code of conduct.
    • [ ] I added an entry to CHANGELOG.md if knowledge of this change could be valuable to users.
    opened by agateau 8
  • Panic for tracks with empty name

    Panic for tracks with empty name

    When opening a file with this format:

    <gpx>
        <!--- metadata --->
        <trk>
            <name></name>
            <!--- rest of track data --->
        </trk>
    </gpx>
    

    gpx panics with the message: no content inside string.

    Is there a reason string::consume is called with allow_empty=false here? Is this construct just invalid and the App I used has generated an invalid gpx file? If that is the case, since all other gpx applications I tested don't have a problem with this, would it make sense to accept this anyways?

    opened by soruh 8
  • Rework parsing: More strict and (hopefully) cleaner

    Rework parsing: More strict and (hopefully) cleaner

    Reworked every parser file, with the exception of extensions.rs.

    Changes and cleanup were mostly:

    • Every parser is now responsible for consuming his own starting and closing tags (previously some parsers would be okay not having any starting tag, and would be used like this). To be able to achieve this any parser that calls further consume functions must use peek() to leave starting tags in the reader for the subparser to handle.
    • Many parsers were accepting any amount of their starting tag, and also consuming any closing tag as valid, ignoring the name. Now exactly one opening tag and matching closing tag is required.
    • Parsers that were already using peek() were doing so via a level of indirection through some form of "ParseEvent" enum, I think I have found a cleaner solution using .clone() on the event which allows us to remove this indirection and parse XmlEvents more directly even with peek().
    • Added some more custom errors, and generally use custom errors more
    opened by Lingepumpe 7
  • Implementing serde (De)Serialize for GPX structs

    Implementing serde (De)Serialize for GPX structs

    • [x] I agree to follow the project's code of conduct.
    • [x] I added an entry to CHANGELOG.md if knowledge of this change could be valuable to users.

    This PR resolves #59, by implementing optional support for (de-)serializing the GPX structs via serde.

    I named the feature flag serde-serialize, same as in the wasm-bindgen crate. Using serde for the feature flag name is not yet possible, since it would require the currently unstable cargo namespaced features implementation. See also the related cargo tracking issue.

    It was asked in #59, whether it would be possible to use GeoJSON, but for my usecase, it would be overkill to deal with additional data structure conversions. I also checked the Rust API guidelines, which mention that it would be good, if structs implemented serde::{Serialize, Deserialize}.

    If the changes are okay and can/should be merged, I'll update the branch with a changelog entry.

    hacktoberfest-accepted 
    opened by mkroehnert 6
  • Apply Clippy Suggestions

    Apply Clippy Suggestions

    • [ x] I agree to follow the project's code of conduct.
    • [ ] I added an entry to CHANGELOG.md if knowledge of this change could be valuable to users.

    Hey folks, I had to burn some spare time and ran clippy -- -W clippy::pedantic against the project. I applied most of the suggestions and now running clippy -- -W clippy::pedantic -A clippy::used_underscore_binding passes.

    The clippy::used_underscore_binding rule still fails because of Waypoint::_type. Renaming it would break the API, hence I did not do that. I suggest to rename the field in some future release to something that aligns with Rust's naming convention ;)

    Additionally, I refactored the consume functions in the parser modules as some of the were super long. If applicable, I introduced a private try_from_attribute function that is used for component initialization.

    Since this PR is mostly about cosmetics and doesn't change any semantics (hopefully), I did not put it in the changelog :P

    opened by 0b11001111 10
  • How to access the time of a waypoint?

    How to access the time of a waypoint?

    Hello,

    Thanks a lot for the crate! This makes handling of gpx files really easy.

    I have one question though: How can I, as a consumer, properly work with the time of a waypoint? Maybe I'm missing it, but although with the newest commit, the Time struct is exported, I can only format it directly to a string. I would like to have it as a chrono DateTime to further do some calculations on it.

    Currently it seems that I have to format it as a String (involving an allocation), just to have it again parsed again by chrono.

    What about a chrono feature of the crate, which could transform the Time as a chrono DateTime?

    opened by gerritsangel 6
  • Time Parsing

    Time Parsing

    Hello everybody,

    first of all thanks for providing this great package!

    I stumbled over a GPX file that contains the following time stamp <time>2021-10-10T09:55:20.952</time> which causes an Rfc3339Error during parsing. The file, however, validates against the GPX 1.1 schema

    $ xmllint --schema http://www.topografix.com/GPX/1/1/gpx.xsd /tmp/test.gpx --noout
    /tmp/test.gpx validates
    

    Both, GPX 1.0 and GPX 1.1 define time stamps as xsd:dateTime which is neither RFC 3339 nor ISO 8601 by definition, although the latter strongly inspired it. See this great visualization for comparison of the standards 😎.

    I suggest to assume ISO 8601 by default. Since the world isn't perfect, I also suggest to implement an fall back on RFC 3339 in error cases or, even better, allow for user defined error handlers. In my case, for instance, I don't really care about the time stamp and would pass a callback that simply ignores the "malformed" input.

    If you're interested, I can start working on a PR 🙃

    opened by 0b11001111 1
  • Allow continuing on unimportant errors

    Allow continuing on unimportant errors

    I have a GPX file, which has a malformed <time> node:

    <time>2022-04-13T11:49:33.749</time>
    

    The rest of the file is fine, but gpx::read fails because of that. Could there be an option to "continue on unimportant errors" for parsing? Thanks.

    opened by fschutt 0
  • allow parsing of arbitrary third-party extensions

    allow parsing of arbitrary third-party extensions

    The GPX schema allows for some tags to include arbitrary XML data in the form of the extensions tag:

    <...>
    Allow any elements from a namespace other than this schema's namespace (lax validation). [0..*]
    </...>
    

    Currently rust-gpx has no functionality that allows this data to be parsed or stored in the resulting Gpx instance. This issue is a tracking issue for this feature.

    enhancement 
    opened by brendanashworth 6
Owner
GeoRust
A collection of geospatial tools and libraries written in Rust
GeoRust
Rust read/write support for well-known text (WKT)

wkt Rust read/write support for well-known text (WKT). License Licensed under either of Apache License, Version 2.0 (LICENSE-APACHE or http://www.apac

GeoRust 40 Dec 11, 2022
Rust read/write support for well-known text (WKT)

wkt Rust read/write support for well-known text (WKT). License Licensed under either of Apache License, Version 2.0 (LICENSE-APACHE or http://www.apac

GeoRust 40 Dec 11, 2022
Read GDAL compatible file formats into polars / geopolars

Read GDAL-compatible geospatial data into Polars and GeoPolars. Supports reading the following geospatial formats into a Polars Dataframe: GeoJSON Sha

Patrick Hayes 5 Nov 27, 2022
Library for serializing the GeoJSON vector GIS file format

geojson Documentation Library for serializing the GeoJSON vector GIS file format Minimum Rust Version This library requires a minimum Rust version of

GeoRust 176 Dec 27, 2022
Library for serializing the GeoJSON vector GIS file format

geojson Documentation Library for serializing the GeoJSON vector GIS file format Minimum Rust Version This library requires a minimum Rust version of

GeoRust 176 Dec 27, 2022
OpenStreetMap flatdata format and compiler

osmflat Flat OpenStreetMap (OSM) data format providing an efficient random data access through memory mapped files. The data format is described and i

null 31 Dec 7, 2022
A TinyVG vector graphics format parsing library.

tinyvg-rs A TinyVG vector graphics format parsing library. Testing This library uses the example files from the TinyVG/examples repo for integration t

null 2 Dec 31, 2021
Convert perf.data files to the Firefox Profiler format

fxprof-perf-convert A converter from the Linux perf perf.data format into the Firefox Profiler format, specifically into the processed profile format.

Markus Stange 12 Sep 19, 2022
Rust crate for performing coordinate transforms

Synopsis A Rust crate use for performing coordinate transformations. The crate relies on nalgebra vectors to perform the coordinate transformations. C

Dave 25 Aug 20, 2022
An fast, offline reverse geocoder (>1,000 HTTP requests per second) in Rust.

Rust Reverse Geocoder A fast reverse geocoder in Rust. Inspired by Python reverse-geocoder. Links Crate 2.0.0 Docs 1.0.1 Docs Description rrgeo takes

Grant Miner 91 Dec 29, 2022
Geospatial primitives and algorithms for Rust

geo Geospatial Primitives, Algorithms, and Utilities The geo crate provides geospatial primitive types such as Point, LineString, and Polygon, and pro

GeoRust 989 Dec 29, 2022
Rust bindings for GDAL

gdal [] GDAL bindings for Rust. So far, you can: open a raster dataset for reading/writing get size and number of bands get/set projection and geo-tra

GeoRust 211 Jan 4, 2023
Rust bindings for the latest stable release of PROJ

PROJ Coordinate transformation via bindings to the PROJ v7.2.1 API. Two coordinate transformation operations are currently provided: projection (and i

GeoRust 96 Dec 21, 2022
Geohash for Rust

Rust-Geohash Rust-Geohash is a Rust library for Geohash algorithm. Ported from node-geohash module. Documentation Docs Check the API doc at docs.rs Li

GeoRust 74 Sep 8, 2022
Google Encoded Polyline encoding & decoding in Rust.

polyline Google Encoded Polyline encoding & decoding in Rust. A Note on Coordinate Order This crate uses Coordinate and LineString types from the geo-

GeoRust 14 Dec 11, 2022
Geocoding library for Rust.

geocoding Rust utilities to enrich addresses, cities, countries, and landmarks with geographic coordinates through third-party geocoding web services.

GeoRust 55 Dec 12, 2022
Geospatial primitives and algorithms for Rust

geo Geospatial Primitives, Algorithms, and Utilities The geo crate provides geospatial primitive types such as Point, LineString, and Polygon, and pro

GeoRust 990 Jan 1, 2023
Rust bindings for GEOS

geos Rust bindings for GEOS C API. The supported geos version is >= 3.5 Disclaimer GEOS can be a tad strict on the validity on the input geometry and

GeoRust 75 Dec 11, 2022
Rust bindings for the latest stable release of PROJ

PROJ Coordinate transformation via bindings to the PROJ v7.2.1 API. Two coordinate transformation operations are currently provided: projection (and i

GeoRust 96 Dec 21, 2022