georust / gpx Goto Github PK
View Code? Open in Web Editor NEWRust read/write support for GPS Exchange Format (GPX)
Home Page: https://crates.io/crates/gpx
License: MIT License
Rust read/write support for GPS Exchange Format (GPX)
Home Page: https://crates.io/crates/gpx
License: MIT License
I ran into an issue where traits implemented on Point
in the geo
crate didn't apply to the Point
objects returned from gpx
file parsing.
Looks like the latest geo
crate uses newer geo_types
version than this crate, so the trait impls don't apply to those types.
For now it's easy to workaround it by converting with something like Point::new(val.lng(), val.lat())
, but it would be even better if this weren't necessary.
Hi there,
My GPS tracker app (Sports Tracker) produces gpx files that contain empty name tags:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<gpx xmlns="http://www.topografix.com/GPX/1/1" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" creator="Sports Tracker" version="1.1" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd">
<metadata>
<name/>
<desc/>
<author><name>Jasper</name></author>
</metadata>
<trk>
<name/>
<trkseg>
<trkpt...
That empty name tag in the metadata results in a NoStringContent
error.
I created a pull request (#97) that fixes this by allowing the name tag to be empty.
If you need any further information or if you'd like me to add a test then please let me know.
No need to reinvent the wheel with our own XML parser. I'm sure there are already a few, which one should we use?
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 🙃
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.
thread 'main' panicked at 'Error parsing gpx file.: Error(InvalidElementLacksAttribute("version", "gpx"), State { next_error: None, backtrace: InternalBacktrace { backtrace: None } })', src/context.rs:160:32
There's a small example on docs.rs, but it's a bit barebones and doesn't cover a potential use case. We should add a more useful example, and feature it on the README. For example, construct a new Gpx object from scratch and save it to a file.
Strava uses the creator attribute in GPX files in a very special way. Not being able to set it when creating a GPX file will prevent Strava from using elevation data when uploading the GPX file there.
From the Strava API docs in https://developers.strava.com/docs/uploads/
Device type is detected in all file types from standard ‘creator’ tags. These tags are then matched to a list of known devices. In some cases the name of the device will be displayed along with the activity details on strava.com.
A generic “with barometer” device is provided to force the system to use the elevation data from TCX and GPX file types. One only needs to add “with barometer” to the end of the creator name.
I suggest having a way to programmatically change the creator attribute from "https://github.com/georust/gpx".
GPX 1.0 is an obsolete spec, but there are a lot of files around. Like whatever gpsbabel still generate that when it download from my GPS logger.
GPX 1.0 needs to be supported (working on a PR for that).
FWIW, the spec is here:
http://www.topografix.com/gpx_manual.asp
In src/parser/waypoint.rs the element "ageofgpsdata" gets parsed into the age
filed of the Waypoint
object. Comparing that with the GPX 1.1 shema, there is no "ageofgpsdata" in a waypoint element. Instead there exists an "ageofdgpsdata" element. That would also be somewhat consistent with the documentation of the age
attribute of the Waypoint
class, which speaks of seconds since the last DGPS update.
The Waypoint
parser should probably be changed to be able to parse "ageofdgpsdata" elements into the age
attribute.
I’m not sure what to do about "ageofgpsdata" elements (without d). Those are actually used in the example file tests/fixtures/with_accuracy.gpx. If there are non-conforming gpx files in the wild that have waypoints with an "ageofgpsdata" element, we should probably be able to read them.
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?
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?
According to the specification, you have 0 or more route in a gpx, so gpx.route
should be a Vec<Route>
and not a Route
.
src/types.rs
uses Time
as use crate::parser::time::Time
, perhaps this should be pub use
?
Hi,
I've got a GPX file coming from QMapShack with extensions that fails to parse, found here: https://pastebin.com/ETVKuhrZ.
I'd expect to at least get a GPX result without extensions, since the library doesn't support them.
GPX library version: 0.9.0
Backtrace if interesting: https://pastebin.com/MKGNt68H
Hi, I'm using gpx
crate in a program together with geo
and geo-types
. When compiling I get:
error[E0308]: mismatched types
--> src/context.rs:166:37
|
166 | coords.push(f.point());
| ^^^^^^^^^ expected struct `geo::Point`, found struct `geo_types::point::Point`
|
= note: expected struct `geo::Point<f64>`
found struct `geo_types::point::Point<f64>`
= note: perhaps two different versions of crate `geo_types` are being used?
error[E0599]: no method named `geodesic_distance` found for struct `geo_types::point::Point<f64>` in the current scope
--> src/context.rs:174:36
|
174 | let d = p1.geodesic_distance(&p2);
| ^^^^^^^^^^^^^^^^^ method not found in `geo_types::point::Point<f64>`
I can solve this updating geo
and geo-types
dependency on a local gpx
crate. How should this work on Rust? Should gpx
always be in sync with latest geo
release? Should gpx
re-export geo
crate? Sorry but I'm not a Rust expert!
It's possible to write out gpx which cannot be read back in with gpx crate itself. In this example case we have string ?>
in Route's name which is not correctly escaped to produce a valid XML output.
Consider the following example program:
use std::io::Cursor;
use gpx;
fn main() {
let g = gpx::Gpx {
version: gpx::GpxVersion::Gpx11,
route: gpx::Route {
name: Some("?>".into()),
.. gpx::Route::default()
},
.. gpx::Gpx::default()
};
let mut buf = Vec::new();
gpx::write(&g, &mut buf).unwrap();
println!("{}", String::from_utf8_lossy(&buf));
let cursor = Cursor::new(&buf);
let _ = gpx::read(cursor).unwrap();
}
and when executed:
$ cargo run -q --example invalid-xml
<?xml version="1.0" encoding="utf-8"?>
<gpx version="1.1" creator="https://github.com/georust/gpx">
<rte>
<name>?></name>
</rte>
</gpx>
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error(Msg("error while parsing XML"), State { next_error: Some(Error { pos: 4:11, kind: Syntax("Unexpected token: ?>") }), backtrace: InternalBacktrace { backtrace: None } })', examples/invalid-xml.rs:18:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
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.
Hello all,
first of all I want to say thank you for your work on the GPX crate.
I am using this crate for a hobby project which allows recording GPS tracks via the webbrowser GPS API and exporting them as GPX. See https://gitlab.com/mkroehnert/trailcorder.
In addition to the existing XML export option, I am currently testing a feature for persisting the recorded data in local storage as JSON objects, which requires deriving serde (De)Serialize for the structs in this crate.
Since it is not easily possible to add serde #derive to structs that are not part of my own crate, I added the required changes in the following commit of my fork: https://github.com/mkroehnert/gpx/commit/26a0b8b1bd9c6348a86c9a30ccff2b963245a05f
Before putting more work into hiding the serde dependency behind a feature flag,
I wanted to ask if this is a contribution you would consider adding/merging,
Hello.
I found out that I have a GPX file with a waypoint name which is empty:
<wpt lat="47.940954" lon="7.158881">
<ele>0</ele>
<name><![CDATA[]]></name>
<desc><![CDATA[]]></desc>
<sym>3</sym>
</wpt>
Looking at the GPX spec: http://www.topografix.com/GPX/1/1/#type_wptType this seems to be valid.
GPX does not place restrictions on the length of this field or the characters contained in it.
But this crate makes it mandatory (allow_empty: false
here):
Line 78 in fec2051
I believe we should allow it empty, don't you think?
Thanks
Hello
A friend sent me a .gpx
file for a trip that we are planning. I tried to load the file with the following simple code:
use gpx;
use std::fs::File;
use std::io::BufReader;
fn main() {
let file = File::open("traces/randonnee-37642110-3-beaulolais.gpx").unwrap();
let reader = BufReader::new(file);
let gpx = gpx::read(reader).unwrap();
println!("{:?}", gpx);
}
I got this error:
thread 'main' panicked at 'called
Result::unwrap()
on anErr
value: NoStringContent', src\main.rs:8:33
The metadata section of the .gpx
file is as follow:
<metadata>
<name>3 BEAULOLAIS</name>
<link href="">
<text></text>
</link>
</metadata>
The application works properly if I remove <text></text>
or add some text between the tags. This is coherent with the error, as the tag is empty (it has NoStringContent XD).
However, both Komoot and Garmin Connect load the file happily.
I believe the gpx
library should have a more relaxed behavior when encountering an empty <text>
tag and just ignore the tag, without raising any error.
Or make write_xml_event
public to more customisation
I have large gpx track and remove indent can decrease size of file and also increase write speed.
The GPX 1.1 spec defines a copyright type which may be in the metadata tag. In gpx v0.8 parsing such a file returns Error(InvalidChildElement("copyright", "metadata"), ...)
.
Metadata:
<copyright> copyrightType </copyright> [0..1]
copyrightType:
<copyright
author="xsd:string [1] ?">
<year> xsd:gYear </year> [0..1] ?
<license> xsd:anyURI </license> [0..1] ?
</copyright>
For my purposes I wouldn't mind if the parser just skips this element and ignores it as long as the file can be parsed.
Reason are track extensions like:
<trk> <name>2017-05-17 06:47:34 Tag</name> <extensions> <gpxx:TrackExtension>
<gpxx:DisplayColor>Cyan</gpxx:DisplayColor> </gpxx:TrackExtension>
</extensions> <trkseg>
Should be fixed by adding an extensions event to consume at tracks.rs:
"extensions" => {
extensions::consume(context)?;
}
the current version of gpx (0.9.1) works badly compared to master, please do a new release
ping @frewsxcv ?
👋 Hi @frewsxcv,
Following up on georust/meta#21, I created a new gpx-publishers team for publishing to crates.io with you as a maintainer (actually since @frewsxcv is an organization owner, GH won't let me mark him as a maintainer, but it'd be redundant permissions anyway 🤷).
Could you please update the crate owners? Specifically:
You two are the only "user owners" of that crate, so only you two can edit that crate's owners:
cd gpx
# 💥 remove large publishing group
cargo owner --remove github:georust:core
# 🔐 add small publishing group
cargo owner --add github:georust:gpx-publishers
# make sure everything looks good 👀
cargo owner --list
And if there's anyone else you'd like to be able to publish the crates, feel free to add them to your publishing team, or as a user-owner. Consider that user-owners, as opposed to owners-via-team, can themselves edit the crate's owners, which could be desirable, or not, depending.
In particular, @brendanashworth, @Lingepumpe, and @oherrala have been active in this repo in the past. Are any of them interested in being added as publishers?
Let me know if you have any questions, or you can review georust/meta#21.
I know this is mentioned in the readme but I though opening an issue would be good so people can subscribe to the status of the issue.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.