fix: Punkte ohne Koordinaten, Fehlertext, neuer Test für Null-Island

- Prüfe lat/lon auf null vor Number-Konvertierung (Number(null) ist 0, nicht NaN)
- Ergänze Test für übersprungene Punkte ohne Koordinaten
- Bessere Fehlermeldung für ungültiges XML

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Daniel Michelberger 2026-08-06 17:30:20 +02:00
parent ef8c05bd7c
commit f89f163e22
2 changed files with 25 additions and 4 deletions

View file

@ -99,6 +99,20 @@ describe('parseGpx', () => {
expect(parseGpx(route).points).toHaveLength(2)
})
it('überspringt Punkte ohne lat/lon statt sie auf 0,0 zu setzen', () => {
const broken = `<?xml version="1.0"?>
<gpx version="1.1" xmlns="http://www.topografix.com/GPX/1/1"><trk><trkseg>
<trkpt lat="49.510" lon="11.430"><ele>300</ele></trkpt>
<trkpt><ele>310</ele></trkpt>
<trkpt lat="49.512" lon="11.432"><ele>320</ele></trkpt>
</trkseg></trk></gpx>`
const r = parseGpx(broken)
expect(r.points).toHaveLength(2)
// Ohne die Prüfung reichte die Bounding-Box bis 0/0
expect(r.bounds[0][0]).toBeGreaterThan(11)
expect(r.distance_m).toBeLessThan(1000)
})
it('wirft bei einer Datei ohne Punkte', () => {
const empty = `<?xml version="1.0"?>
<gpx version="1.1" xmlns="http://www.topografix.com/GPX/1/1"></gpx>`

View file

@ -115,7 +115,7 @@ export function parseGpx(xml: string): ParsedGpx {
const doc = new DOMParser().parseFromString(xml, 'application/xml')
if (doc.querySelector('parsererror')) {
throw new Error('Die Datei ist ungültig.')
throw new Error('Die GPX-Datei ist ungültig.')
}
// Manche Programme exportieren Routen (rtept) statt Tracks (trkpt).
@ -130,8 +130,15 @@ export function parseGpx(xml: string): ParsedGpx {
const points: TrackPoint[] = []
for (const n of nodes) {
const lat = Number(n.getAttribute('lat'))
const lng = Number(n.getAttribute('lon'))
const latAttr = n.getAttribute('lat')
const lngAttr = n.getAttribute('lon')
// Number(null) ist 0, nicht NaN — ohne diese Prüfung landen Punkte
// ohne Koordinaten bei 0/0 im Golf von Guinea und verfälschen
// Streckenlänge und Bounding-Box.
if (latAttr === null || lngAttr === null) continue
const lat = Number(latAttr)
const lng = Number(lngAttr)
if (!Number.isFinite(lat) || !Number.isFinite(lng)) continue
const eleText = n.getElementsByTagName('ele')[0]?.textContent
@ -171,7 +178,7 @@ export function parseGpx(xml: string): ParsedGpx {
// Abstieg über Schwelle: neuer Bezugspunkt, aber nicht gezählt
lastCountedEle = ele
}
// Kleine Schwankungen (-3...+3) ignorieren, Bezugspunkt bleibt
// Kleine Schwankungen (unter 3 m) ignorieren, Bezugspunkt bleibt
}
}