diff --git a/gpx-rs/engine/data/self_closing_points.gpx b/gpx-rs/engine/data/self_closing_points.gpx new file mode 100644 index 000000000..2b119cd85 --- /dev/null +++ b/gpx-rs/engine/data/self_closing_points.gpx @@ -0,0 +1,26 @@ + + + + self closing points + Points without children are self-closing elements. + + 2.0 + + + + + with children + + + track + + + 12.5 + + + + + + + diff --git a/gpx-rs/engine/src/core/io/parse.rs b/gpx-rs/engine/src/core/io/parse.rs index 2e0871ece..4650c3738 100644 --- a/gpx-rs/engine/src/core/io/parse.rs +++ b/gpx-rs/engine/src/core/io/parse.rs @@ -114,6 +114,30 @@ pub fn parse(data: &[u8], categories: &mut TrackpointCategories) -> Result stack.push(GPXElement::Width), _ => (), }, + // Self-closing points (``), which have no children + Ok(Event::Empty(e)) => match e.name().as_ref() { + "trkpt" => { + if let Some(GPXElement::Segment(trkseg)) = stack.last_mut() { + trkpt_chunk.trkpt.push(Trackpoint { + coordinates: parse_coordinates(e.attributes()), + ..Default::default() + }); + if trkpt_chunk.is_full() { + trkseg.push(std::mem::take(&mut trkpt_chunk)); + } + } + } + "wpt" => { + wpt_chunk.wpt.push(Waypoint { + coordinates: parse_coordinates(e.attributes()), + ..Default::default() + }); + if wpt_chunk.is_full() { + gpx.wpt.push(Rc::new(std::mem::take(&mut wpt_chunk))); + } + } + _ => (), + }, Ok(Event::End(e)) => match e.name().as_ref() { "gpx" => { if !wpt_chunk.wpt.is_empty() { @@ -363,6 +387,30 @@ mod tests { .unwrap() } + #[test] + fn test_parse_self_closing_points() { + let gpx = parse_data("self_closing_points"); + + assert_eq!(gpx.info.name, "self closing points"); + let wpt: Vec<_> = gpx.wpt.iter().flat_map(|chunk| &chunk.wpt).collect(); + assert_eq!(wpt.len(), 3); + assert_eq!(wpt[0].coordinates.lat, 50.0); + assert_eq!(wpt[0].name, None); + assert_eq!(wpt[1].name.as_deref(), Some("with children")); + assert_eq!(wpt[2].coordinates.lng, 4.2); + + assert_eq!(gpx.trk.len(), 1); + let trk = &gpx.trk[0]; + assert_eq!(trk.trkseg.len(), 2); + let seg = &trk.trkseg[0]; + assert_eq!(seg.len(), 3); + assert_eq!(seg[0].coordinates.lat, 50.0); + assert_eq!(seg[0].ele, 0.0); + assert_eq!(seg[1].ele, 12.5); + assert_eq!(seg[2].coordinates.lng, 4.02); + assert_eq!(trk.trkseg[1].len(), 1); + } + #[test] fn test_parse_simple() { let gpx = parse_data("simple");