handle self closing elements

This commit is contained in:
vcoppe
2026-10-04 22:01:23 +02:00
parent c6bd5b06e8
commit da8a9e3d84
2 changed files with 74 additions and 0 deletions
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<gpx version="1.1" creator="gpx.studio" xmlns="http://www.topografix.com/GPX/1/1"
xmlns:ext="https://example.com/ext/0.1">
<metadata>
<name>self closing points</name>
<desc>Points without children are self-closing elements.</desc>
<extensions>
<ext:version>2.0</ext:version>
<ext:paths/>
</extensions>
</metadata>
<wpt lat="50.0" lon="4.0"/>
<wpt lat="50.1" lon="4.1"><name>with children</name></wpt>
<wpt lat="50.2" lon="4.2"/>
<trk>
<name>track</name>
<trkseg>
<trkpt lat="50.00" lon="4.00"/>
<trkpt lat="50.01" lon="4.01"><ele>12.5</ele></trkpt>
<trkpt lat="50.02" lon="4.02"/>
</trkseg>
<trkseg>
<trkpt lat="51.00" lon="5.00"/>
</trkseg>
</trk>
</gpx>
+48
View File
@@ -114,6 +114,30 @@ pub fn parse(data: &[u8], categories: &mut TrackpointCategories) -> Result<File,
e if e.ends_with("width") => stack.push(GPXElement::Width), e if e.ends_with("width") => stack.push(GPXElement::Width),
_ => (), _ => (),
}, },
// Self-closing points (`<trkpt lat=".." lon=".."/>`), 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() { Ok(Event::End(e)) => match e.name().as_ref() {
"gpx" => { "gpx" => {
if !wpt_chunk.wpt.is_empty() { if !wpt_chunk.wpt.is_empty() {
@@ -363,6 +387,30 @@ mod tests {
.unwrap() .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] #[test]
fn test_parse_simple() { fn test_parse_simple() {
let gpx = parse_data("simple"); let gpx = parse_data("simple");