mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-09-03 17:12:31 +00:00
fix extensions and attributes
This commit is contained in:
@@ -1,11 +1,11 @@
|
|||||||
import { XMLParser } from "fast-xml-parser";
|
import { XMLParser, XMLBuilder } from "fast-xml-parser";
|
||||||
import { GPXFile } from "./types";
|
import { GPXFile } from "./types";
|
||||||
|
|
||||||
export function parseGPX(gpxData: string): GPXFile {
|
export function parseGPX(gpxData: string): GPXFile {
|
||||||
const parser = new XMLParser({
|
const parser = new XMLParser({
|
||||||
ignoreAttributes: false,
|
ignoreAttributes: false,
|
||||||
attributeNamePrefix: "",
|
attributeNamePrefix: "",
|
||||||
removeNSPrefix: true,
|
attributesGroupName: 'attributes',
|
||||||
isArray: (name: string) => {
|
isArray: (name: string) => {
|
||||||
return name === 'trk' || name === 'trkseg' || name === 'trkpt' || name === 'wpt';
|
return name === 'trk' || name === 'trkseg' || name === 'trkpt' || name === 'wpt';
|
||||||
},
|
},
|
||||||
@@ -18,7 +18,7 @@ export function parseGPX(gpxData: string): GPXFile {
|
|||||||
transformTagName(tagName: string) {
|
transformTagName(tagName: string) {
|
||||||
if (tagName === 'power') {
|
if (tagName === 'power') {
|
||||||
// Transform the simple <power> tag to the more complex <gpxpx:PowerExtension> tag, the nested <gpxpx:PowerInWatts> tag is then handled by the tagValueProcessor
|
// Transform the simple <power> tag to the more complex <gpxpx:PowerExtension> tag, the nested <gpxpx:PowerInWatts> tag is then handled by the tagValueProcessor
|
||||||
return 'PowerExtension';
|
return 'gpxpx:PowerExtension';
|
||||||
}
|
}
|
||||||
return tagName;
|
return tagName;
|
||||||
},
|
},
|
||||||
@@ -32,30 +32,69 @@ export function parseGPX(gpxData: string): GPXFile {
|
|||||||
return new Date(tagValue);
|
return new Date(tagValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tagName === 'hr' || tagName === 'cad' || tagName === 'atemp' || tagName === 'PowerInWatts' || tagName === 'opacity' || tagName === 'weight') {
|
if (tagName === 'gpxtpx:hr' || tagName === 'gpxtpx:cad' || tagName === 'gpxtpx:atemp' || tagName === 'gpxpx:PowerInWatts' || tagName === 'opacity' || tagName === 'weight') {
|
||||||
return parseFloat(tagValue);
|
return parseFloat(tagValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tagName === 'PowerExtension') {
|
if (tagName === 'gpxpx:PowerExtension') {
|
||||||
// Finish the transformation of the simple <power> tag to the more complex <gpxpx:PowerExtension> tag
|
// Finish the transformation of the simple <power> tag to the more complex <gpxpx:PowerExtension> tag
|
||||||
// Note that this only targets the transformed <power> tag, since it must be a leaf node
|
// Note that this only targets the transformed <power> tag, since it must be a leaf node
|
||||||
return {
|
return {
|
||||||
'PowerInWatts': parseFloat(tagValue)
|
'gpxpx:PowerInWatts': parseFloat(tagValue)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tagValue;
|
return tagValue;
|
||||||
},
|
},
|
||||||
transformAttributeName(attributeName) {
|
|
||||||
if (attributeName !== 'lat' && attributeName !== 'lon' && attributeName !== 'creator' && attributeName !== 'href') {
|
|
||||||
return `@_${attributeName}`;
|
|
||||||
}
|
|
||||||
return attributeName;
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const parsed = parser.parse(gpxData);
|
const parsed = parser.parse(gpxData);
|
||||||
|
|
||||||
return parsed.gpx;
|
return parsed.gpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function buildGPX(gpx: GPXFile): string {
|
||||||
|
const builder = new XMLBuilder({
|
||||||
|
format: true,
|
||||||
|
ignoreAttributes: false,
|
||||||
|
attributeNamePrefix: "",
|
||||||
|
attributesGroupName: 'attributes',
|
||||||
|
suppressEmptyNode: true,
|
||||||
|
tagValueProcessor: (tagName: string, tagValue: unknown): string => {
|
||||||
|
if (tagValue instanceof Date) {
|
||||||
|
return tagValue.toISOString();
|
||||||
|
}
|
||||||
|
return tagValue.toString();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
gpx.attributes.creator = 'https://gpx.studio';
|
||||||
|
gpx.attributes['version'] = '1.1';
|
||||||
|
gpx.attributes['xmlns'] = 'http://www.topografix.com/GPX/1/1';
|
||||||
|
gpx.attributes['xmlns:xsi'] = 'http://www.w3.org/2001/XMLSchema-instance';
|
||||||
|
gpx.attributes['xsi:schemaLocation'] = 'http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.garmin.com/xmlschemas/PowerExtension/v1 http://www.garmin.com/xmlschemas/PowerExtensionv1.xsd http://www.topografix.com/GPX/gpx_style/0/2 http://www.topografix.com/GPX/gpx_style/0/2/gpx_style.xsd';
|
||||||
|
gpx.attributes['xmlns:gpxtpx'] = 'http://www.garmin.com/xmlschemas/TrackPointExtension/v1';
|
||||||
|
gpx.attributes['xmlns:gpxx'] = 'http://www.garmin.com/xmlschemas/GpxExtensions/v3';
|
||||||
|
gpx.attributes['xmlns:gpxpx'] = 'http://www.garmin.com/xmlschemas/PowerExtension/v1';
|
||||||
|
gpx.attributes['xmlns:gpx_style'] = 'http://www.topografix.com/GPX/gpx_style/0/2';
|
||||||
|
gpx.metadata.author = {
|
||||||
|
name: 'gpx.studio',
|
||||||
|
link: {
|
||||||
|
attributes: {
|
||||||
|
href: 'https://gpx.studio',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return builder.build({
|
||||||
|
"?xml": {
|
||||||
|
attributes: {
|
||||||
|
version: "1.0",
|
||||||
|
encoding: "UTF-8",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
gpx
|
||||||
|
});
|
||||||
|
}
|
@@ -1,10 +1,15 @@
|
|||||||
export type GPXFile = {
|
export type GPXFile = {
|
||||||
creator: string;
|
attributes: GPXFileAttributes;
|
||||||
metadata: Metadata;
|
metadata: Metadata;
|
||||||
wpt: Waypoint[];
|
wpt: Waypoint[];
|
||||||
trk: Track[];
|
trk: Track[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type GPXFileAttributes = {
|
||||||
|
creator: string;
|
||||||
|
[key: string]: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type Metadata = {
|
export type Metadata = {
|
||||||
name?: string;
|
name?: string;
|
||||||
desc?: string;
|
desc?: string;
|
||||||
@@ -14,14 +19,17 @@ export type Metadata = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type Link = {
|
export type Link = {
|
||||||
href: string;
|
attributes: LinkAttributes;
|
||||||
text?: string;
|
text?: string;
|
||||||
type?: string;
|
type?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type LinkAttributes = {
|
||||||
|
href: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type Waypoint = {
|
export type Waypoint = {
|
||||||
lat: number;
|
attributes: Coordinates;
|
||||||
lon: number;
|
|
||||||
ele?: number;
|
ele?: number;
|
||||||
time?: Date;
|
time?: Date;
|
||||||
name?: string;
|
name?: string;
|
||||||
@@ -32,6 +40,11 @@ export type Waypoint = {
|
|||||||
type?: string;
|
type?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type Coordinates = {
|
||||||
|
lat: number;
|
||||||
|
lon: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type Track = {
|
export type Track = {
|
||||||
name?: string;
|
name?: string;
|
||||||
cmt?: string;
|
cmt?: string;
|
||||||
@@ -44,7 +57,7 @@ export type Track = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type TrackExtensions = {
|
export type TrackExtensions = {
|
||||||
line?: LineStyleExtension;
|
'gpx_style:line'?: LineStyleExtension;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LineStyleExtension = {
|
export type LineStyleExtension = {
|
||||||
@@ -58,29 +71,28 @@ export type TrackSegment = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type TrackPoint = {
|
export type TrackPoint = {
|
||||||
lat: number;
|
attributes: Coordinates;
|
||||||
lon: number;
|
|
||||||
ele?: number;
|
ele?: number;
|
||||||
time?: Date;
|
time?: Date;
|
||||||
extensions?: TrackPointExtensions;
|
extensions?: TrackPointExtensions;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TrackPointExtensions = {
|
export type TrackPointExtensions = {
|
||||||
TrackPointExtension?: TrackPointExtension;
|
'gpxtpx:TrackPointExtension'?: TrackPointExtension;
|
||||||
PowerExtension?: PowerExtension;
|
'gpxpx:PowerExtension'?: PowerExtension;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TrackPointExtension = {
|
export type TrackPointExtension = {
|
||||||
hr?: number;
|
'gpxtpx:hr'?: number;
|
||||||
cad?: number;
|
'gpxtpx:cad'?: number;
|
||||||
atemp?: number;
|
'gpxtpx:atemp'?: number;
|
||||||
Extensions?: {
|
'gpxtpx:Extensions'?: {
|
||||||
surface?: string;
|
surface?: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PowerExtension = {
|
export type PowerExtension = {
|
||||||
PowerInWatts?: number;
|
'gpxpx:PowerInWatts'?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Author = {
|
export type Author = {
|
||||||
|
@@ -1,13 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/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/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.topografix.com/GPX/gpx_style/0/2 http://www.topografix.com/GPX/gpx_style/0/2/gpx_style.xsd" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3" xmlns:gpx_style="http://www.topografix.com/GPX/gpx_style/0/2" version="1.1" creator="https://gpx.studio">
|
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
<metadata>
|
xmlns="http://www.topografix.com/GPX/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/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.topografix.com/GPX/gpx_style/0/2 http://www.topografix.com/GPX/gpx_style/0/2/gpx_style.xsd"
|
||||||
|
xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1"
|
||||||
|
xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3"
|
||||||
|
xmlns:gpx_style="http://www.topografix.com/GPX/gpx_style/0/2" version="1.1" creator="https://gpx.studio">
|
||||||
|
<metadata>
|
||||||
<name>simple</name>
|
<name>simple</name>
|
||||||
<author>
|
<author>
|
||||||
<name>gpx.studio</name>
|
<name>gpx.studio</name>
|
||||||
<link href="https://gpx.studio"></link>
|
<link href="https://gpx.studio"></link>
|
||||||
</author>
|
</author>
|
||||||
</metadata>
|
</metadata>
|
||||||
<trk>
|
<trk>
|
||||||
<name>simple</name>
|
<name>simple</name>
|
||||||
<type>Cycling</type>
|
<type>Cycling</type>
|
||||||
<trkseg>
|
<trkseg>
|
||||||
@@ -252,5 +256,5 @@
|
|||||||
<ele>129.5</ele>
|
<ele>129.5</ele>
|
||||||
</trkpt>
|
</trkpt>
|
||||||
</trkseg>
|
</trkseg>
|
||||||
</trk>
|
</trk>
|
||||||
</gpx>
|
</gpx>
|
@@ -1,13 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/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/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.topografix.com/GPX/gpx_style/0/2 http://www.topografix.com/GPX/gpx_style/0/2/gpx_style.xsd" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3" xmlns:gpx_style="http://www.topografix.com/GPX/gpx_style/0/2" version="1.1" creator="https://gpx.studio">
|
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
<metadata>
|
xmlns="http://www.topografix.com/GPX/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/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.topografix.com/GPX/gpx_style/0/2 http://www.topografix.com/GPX/gpx_style/0/2/gpx_style.xsd"
|
||||||
|
xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1"
|
||||||
|
xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3"
|
||||||
|
xmlns:gpx_style="http://www.topografix.com/GPX/gpx_style/0/2" version="1.1" creator="https://gpx.studio">
|
||||||
|
<metadata>
|
||||||
<name>with_segments</name>
|
<name>with_segments</name>
|
||||||
<author>
|
<author>
|
||||||
<name>gpx.studio</name>
|
<name>gpx.studio</name>
|
||||||
<link href="https://gpx.studio"></link>
|
<link href="https://gpx.studio"></link>
|
||||||
</author>
|
</author>
|
||||||
</metadata>
|
</metadata>
|
||||||
<trk>
|
<trk>
|
||||||
<name>with_segments</name>
|
<name>with_segments</name>
|
||||||
<type>Cycling</type>
|
<type>Cycling</type>
|
||||||
<trkseg>
|
<trkseg>
|
||||||
@@ -245,5 +249,5 @@
|
|||||||
<ele>129.5</ele>
|
<ele>129.5</ele>
|
||||||
</trkpt>
|
</trkpt>
|
||||||
</trkseg>
|
</trkseg>
|
||||||
</trk>
|
</trk>
|
||||||
</gpx>
|
</gpx>
|
@@ -1,13 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/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/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.topografix.com/GPX/gpx_style/0/2 http://www.topografix.com/GPX/gpx_style/0/2/gpx_style.xsd" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3" xmlns:gpx_style="http://www.topografix.com/GPX/gpx_style/0/2" version="1.1" creator="https://gpx.studio">
|
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
<metadata>
|
xmlns="http://www.topografix.com/GPX/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/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.topografix.com/GPX/gpx_style/0/2 http://www.topografix.com/GPX/gpx_style/0/2/gpx_style.xsd"
|
||||||
|
xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1"
|
||||||
|
xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3"
|
||||||
|
xmlns:gpx_style="http://www.topografix.com/GPX/gpx_style/0/2" version="1.1" creator="https://gpx.studio">
|
||||||
|
<metadata>
|
||||||
<name>with_time</name>
|
<name>with_time</name>
|
||||||
<author>
|
<author>
|
||||||
<name>gpx.studio</name>
|
<name>gpx.studio</name>
|
||||||
<link href="https://gpx.studio"></link>
|
<link href="https://gpx.studio"></link>
|
||||||
</author>
|
</author>
|
||||||
</metadata>
|
</metadata>
|
||||||
<trk>
|
<trk>
|
||||||
<name>with_time</name>
|
<name>with_time</name>
|
||||||
<type>Cycling</type>
|
<type>Cycling</type>
|
||||||
<trkseg>
|
<trkseg>
|
||||||
@@ -332,5 +336,5 @@
|
|||||||
<time>2023-12-31T23:06:40.567Z</time>
|
<time>2023-12-31T23:06:40.567Z</time>
|
||||||
</trkpt>
|
</trkpt>
|
||||||
</trkseg>
|
</trkseg>
|
||||||
</trk>
|
</trk>
|
||||||
</gpx>
|
</gpx>
|
@@ -1,20 +1,24 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.topografix.com/GPX/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/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.topografix.com/GPX/gpx_style/0/2 http://www.topografix.com/GPX/gpx_style/0/2/gpx_style.xsd" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3" xmlns:gpx_style="http://www.topografix.com/GPX/gpx_style/0/2" version="1.1" creator="https://gpx.studio">
|
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
<metadata>
|
xmlns="http://www.topografix.com/GPX/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/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd http://www.topografix.com/GPX/gpx_style/0/2 http://www.topografix.com/GPX/gpx_style/0/2/gpx_style.xsd"
|
||||||
|
xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1"
|
||||||
|
xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3"
|
||||||
|
xmlns:gpx_style="http://www.topografix.com/GPX/gpx_style/0/2" version="1.1" creator="https://gpx.studio">
|
||||||
|
<metadata>
|
||||||
<name>with_waypoint</name>
|
<name>with_waypoint</name>
|
||||||
<author>
|
<author>
|
||||||
<name>gpx.studio</name>
|
<name>gpx.studio</name>
|
||||||
<link href="https://gpx.studio"></link>
|
<link href="https://gpx.studio"></link>
|
||||||
</author>
|
</author>
|
||||||
</metadata>
|
</metadata>
|
||||||
<wpt lat="50.7836710064975" lon="4.410764082658738">
|
<wpt lat="50.7836710064975" lon="4.410764082658738">
|
||||||
<ele>122.0</ele>
|
<ele>122.0</ele>
|
||||||
<name>Waypoint</name>
|
<name>Waypoint</name>
|
||||||
<cmt>Comment</cmt>
|
<cmt>Comment</cmt>
|
||||||
<desc>Description</desc>
|
<desc>Description</desc>
|
||||||
<sym>Bike Trail</sym>
|
<sym>Bike Trail</sym>
|
||||||
</wpt>
|
</wpt>
|
||||||
<trk>
|
<trk>
|
||||||
<name>with_waypoint</name>
|
<name>with_waypoint</name>
|
||||||
<type>Cycling</type>
|
<type>Cycling</type>
|
||||||
<trkseg>
|
<trkseg>
|
||||||
@@ -259,5 +263,5 @@
|
|||||||
<ele>129.5</ele>
|
<ele>129.5</ele>
|
||||||
</trkpt>
|
</trkpt>
|
||||||
</trkseg>
|
</trkseg>
|
||||||
</trk>
|
</trk>
|
||||||
</gpx>
|
</gpx>
|
@@ -1,17 +1,17 @@
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
|
||||||
import { parseGPX } from '../src/io';
|
import { parseGPX, buildGPX } from '../src/io';
|
||||||
|
|
||||||
describe("Parsing tests", () => {
|
describe("Parsing", () => {
|
||||||
it("Simple", () => {
|
it("Simple", () => {
|
||||||
const path = "test-data/simple.gpx";
|
const path = "test-data/simple.gpx";
|
||||||
const data = fs.readFileSync(path, 'utf8');
|
const data = fs.readFileSync(path, 'utf8');
|
||||||
const result = parseGPX(data);
|
const result = parseGPX(data);
|
||||||
|
|
||||||
expect(result.creator).toBe("https://gpx.studio");
|
expect(result.attributes.creator).toBe("https://gpx.studio");
|
||||||
expect(result.metadata.name).toBe("simple");
|
expect(result.metadata.name).toBe("simple");
|
||||||
expect(result.metadata.author.name).toBe("gpx.studio");
|
expect(result.metadata.author.name).toBe("gpx.studio");
|
||||||
expect(result.metadata.author.link.href).toBe("https://gpx.studio");
|
expect(result.metadata.author.link.attributes.href).toBe("https://gpx.studio");
|
||||||
|
|
||||||
expect(result.trk.length).toBe(1);
|
expect(result.trk.length).toBe(1);
|
||||||
|
|
||||||
@@ -25,13 +25,14 @@ describe("Parsing tests", () => {
|
|||||||
|
|
||||||
for (let i = 0; i < segment.trkpt.length; i++) {
|
for (let i = 0; i < segment.trkpt.length; i++) {
|
||||||
const point = segment.trkpt[i];
|
const point = segment.trkpt[i];
|
||||||
expect(point).toHaveProperty('lat');
|
expect(point).toHaveProperty('attributes');
|
||||||
expect(point).toHaveProperty('lon');
|
expect(point.attributes).toHaveProperty('lat');
|
||||||
|
expect(point.attributes).toHaveProperty('lon');
|
||||||
expect(point).toHaveProperty('ele');
|
expect(point).toHaveProperty('ele');
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(segment.trkpt[0].lat).toBe(50.790867);
|
expect(segment.trkpt[0].attributes.lat).toBe(50.790867);
|
||||||
expect(segment.trkpt[0].lon).toBe(4.404968);
|
expect(segment.trkpt[0].attributes.lon).toBe(4.404968);
|
||||||
expect(segment.trkpt[0].ele).toBe(109.0);
|
expect(segment.trkpt[0].ele).toBe(109.0);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -74,8 +75,8 @@ describe("Parsing tests", () => {
|
|||||||
expect(result.wpt.length).toBe(1);
|
expect(result.wpt.length).toBe(1);
|
||||||
|
|
||||||
const waypoint = result.wpt[0];
|
const waypoint = result.wpt[0];
|
||||||
expect(waypoint.lat).toBe(50.7836710064975);
|
expect(waypoint.attributes.lat).toBe(50.7836710064975);
|
||||||
expect(waypoint.lon).toBe(4.410764082658738);
|
expect(waypoint.attributes.lon).toBe(4.410764082658738);
|
||||||
expect(waypoint.ele).toBe(122.0);
|
expect(waypoint.ele).toBe(122.0);
|
||||||
expect(waypoint.name).toBe("Waypoint");
|
expect(waypoint.name).toBe("Waypoint");
|
||||||
expect(waypoint.cmt).toBe("Comment");
|
expect(waypoint.cmt).toBe("Comment");
|
||||||
@@ -109,12 +110,12 @@ describe("Parsing tests", () => {
|
|||||||
|
|
||||||
for (let i = 0; i < segment.trkpt.length; i++) {
|
for (let i = 0; i < segment.trkpt.length; i++) {
|
||||||
expect(segment.trkpt[i]).toHaveProperty('extensions');
|
expect(segment.trkpt[i]).toHaveProperty('extensions');
|
||||||
expect(segment.trkpt[i].extensions).toHaveProperty('TrackPointExtension');
|
expect(segment.trkpt[i].extensions).toHaveProperty('gpxtpx:TrackPointExtension');
|
||||||
expect(segment.trkpt[i].extensions.TrackPointExtension).toHaveProperty('hr');
|
expect(segment.trkpt[i].extensions['gpxtpx:TrackPointExtension']).toHaveProperty('gpxtpx:hr');
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(segment.trkpt[0].extensions.TrackPointExtension.hr).toBe(150);
|
expect(segment.trkpt[0].extensions['gpxtpx:TrackPointExtension']['gpxtpx:hr']).toBe(150);
|
||||||
expect(segment.trkpt[segment.trkpt.length - 1].extensions.TrackPointExtension.hr).toBe(160);
|
expect(segment.trkpt[segment.trkpt.length - 1].extensions['gpxtpx:TrackPointExtension']['gpxtpx:hr']).toBe(160);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Cadence", () => {
|
it("Cadence", () => {
|
||||||
@@ -127,12 +128,12 @@ describe("Parsing tests", () => {
|
|||||||
|
|
||||||
for (let i = 0; i < segment.trkpt.length; i++) {
|
for (let i = 0; i < segment.trkpt.length; i++) {
|
||||||
expect(segment.trkpt[i]).toHaveProperty('extensions');
|
expect(segment.trkpt[i]).toHaveProperty('extensions');
|
||||||
expect(segment.trkpt[i].extensions).toHaveProperty('TrackPointExtension');
|
expect(segment.trkpt[i].extensions).toHaveProperty('gpxtpx:TrackPointExtension');
|
||||||
expect(segment.trkpt[i].extensions.TrackPointExtension).toHaveProperty('cad');
|
expect(segment.trkpt[i].extensions['gpxtpx:TrackPointExtension']).toHaveProperty('gpxtpx:cad');
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(segment.trkpt[0].extensions.TrackPointExtension.cad).toBe(80);
|
expect(segment.trkpt[0].extensions['gpxtpx:TrackPointExtension']['gpxtpx:cad']).toBe(80);
|
||||||
expect(segment.trkpt[segment.trkpt.length - 1].extensions.TrackPointExtension.cad).toBe(90);
|
expect(segment.trkpt[segment.trkpt.length - 1].extensions['gpxtpx:TrackPointExtension']['gpxtpx:cad']).toBe(90);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Temperature", () => {
|
it("Temperature", () => {
|
||||||
@@ -145,12 +146,12 @@ describe("Parsing tests", () => {
|
|||||||
|
|
||||||
for (let i = 0; i < segment.trkpt.length; i++) {
|
for (let i = 0; i < segment.trkpt.length; i++) {
|
||||||
expect(segment.trkpt[i]).toHaveProperty('extensions');
|
expect(segment.trkpt[i]).toHaveProperty('extensions');
|
||||||
expect(segment.trkpt[i].extensions).toHaveProperty('TrackPointExtension');
|
expect(segment.trkpt[i].extensions).toHaveProperty('gpxtpx:TrackPointExtension');
|
||||||
expect(segment.trkpt[i].extensions.TrackPointExtension).toHaveProperty('atemp');
|
expect(segment.trkpt[i].extensions['gpxtpx:TrackPointExtension']).toHaveProperty('gpxtpx:atemp');
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(segment.trkpt[0].extensions.TrackPointExtension.atemp).toBe(21);
|
expect(segment.trkpt[0].extensions['gpxtpx:TrackPointExtension']['gpxtpx:atemp']).toBe(21);
|
||||||
expect(segment.trkpt[segment.trkpt.length - 1].extensions.TrackPointExtension.atemp).toBe(22);
|
expect(segment.trkpt[segment.trkpt.length - 1].extensions['gpxtpx:TrackPointExtension']['gpxtpx:atemp']).toBe(22);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Power 1", () => {
|
it("Power 1", () => {
|
||||||
@@ -163,12 +164,12 @@ describe("Parsing tests", () => {
|
|||||||
|
|
||||||
for (let i = 0; i < segment.trkpt.length; i++) {
|
for (let i = 0; i < segment.trkpt.length; i++) {
|
||||||
expect(segment.trkpt[i]).toHaveProperty('extensions');
|
expect(segment.trkpt[i]).toHaveProperty('extensions');
|
||||||
expect(segment.trkpt[i].extensions).toHaveProperty('PowerExtension');
|
expect(segment.trkpt[i].extensions).toHaveProperty('gpxpx:PowerExtension');
|
||||||
expect(segment.trkpt[i].extensions.PowerExtension).toHaveProperty('PowerInWatts');
|
expect(segment.trkpt[i].extensions['gpxpx:PowerExtension']).toHaveProperty('gpxpx:PowerInWatts');
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(segment.trkpt[0].extensions.PowerExtension.PowerInWatts).toBe(200);
|
expect(segment.trkpt[0].extensions['gpxpx:PowerExtension']['gpxpx:PowerInWatts']).toBe(200);
|
||||||
expect(segment.trkpt[segment.trkpt.length - 1].extensions.PowerExtension.PowerInWatts).toBe(210);
|
expect(segment.trkpt[segment.trkpt.length - 1].extensions['gpxpx:PowerExtension']['gpxpx:PowerInWatts']).toBe(210);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Power 2", () => {
|
it("Power 2", () => {
|
||||||
@@ -181,12 +182,12 @@ describe("Parsing tests", () => {
|
|||||||
|
|
||||||
for (let i = 0; i < segment.trkpt.length; i++) {
|
for (let i = 0; i < segment.trkpt.length; i++) {
|
||||||
expect(segment.trkpt[i]).toHaveProperty('extensions');
|
expect(segment.trkpt[i]).toHaveProperty('extensions');
|
||||||
expect(segment.trkpt[i].extensions).toHaveProperty('PowerExtension');
|
expect(segment.trkpt[i].extensions).toHaveProperty('gpxpx:PowerExtension');
|
||||||
expect(segment.trkpt[i].extensions.PowerExtension).toHaveProperty('PowerInWatts');
|
expect(segment.trkpt[i].extensions['gpxpx:PowerExtension']).toHaveProperty('gpxpx:PowerInWatts');
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(segment.trkpt[0].extensions.PowerExtension.PowerInWatts).toBe(200);
|
expect(segment.trkpt[0].extensions['gpxpx:PowerExtension']['gpxpx:PowerInWatts']).toBe(200);
|
||||||
expect(segment.trkpt[segment.trkpt.length - 1].extensions.PowerExtension.PowerInWatts).toBe(210);
|
expect(segment.trkpt[segment.trkpt.length - 1].extensions['gpxpx:PowerExtension']['gpxpx:PowerInWatts']).toBe(210);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Surface", () => {
|
it("Surface", () => {
|
||||||
@@ -199,13 +200,13 @@ describe("Parsing tests", () => {
|
|||||||
|
|
||||||
for (let i = 0; i < segment.trkpt.length; i++) {
|
for (let i = 0; i < segment.trkpt.length; i++) {
|
||||||
expect(segment.trkpt[i]).toHaveProperty('extensions');
|
expect(segment.trkpt[i]).toHaveProperty('extensions');
|
||||||
expect(segment.trkpt[i].extensions).toHaveProperty('TrackPointExtension');
|
expect(segment.trkpt[i].extensions).toHaveProperty('gpxtpx:TrackPointExtension');
|
||||||
expect(segment.trkpt[i].extensions.TrackPointExtension).toHaveProperty('Extensions');
|
expect(segment.trkpt[i].extensions['gpxtpx:TrackPointExtension']).toHaveProperty('gpxtpx:Extensions');
|
||||||
expect(segment.trkpt[i].extensions.TrackPointExtension.Extensions).toHaveProperty('surface');
|
expect(segment.trkpt[i].extensions['gpxtpx:TrackPointExtension']['gpxtpx:Extensions']).toHaveProperty('surface');
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(segment.trkpt[0].extensions.TrackPointExtension.Extensions.surface).toBe("asphalt");
|
expect(segment.trkpt[0].extensions['gpxtpx:TrackPointExtension']['gpxtpx:Extensions'].surface).toBe("asphalt");
|
||||||
expect(segment.trkpt[segment.trkpt.length - 1].extensions.TrackPointExtension.Extensions.surface).toBe("cobblestone");
|
expect(segment.trkpt[segment.trkpt.length - 1].extensions['gpxtpx:TrackPointExtension']['gpxtpx:Extensions'].surface).toBe("cobblestone");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Track style", () => {
|
it("Track style", () => {
|
||||||
@@ -216,14 +217,148 @@ describe("Parsing tests", () => {
|
|||||||
const track = result.trk[0];
|
const track = result.trk[0];
|
||||||
|
|
||||||
expect(track).toHaveProperty('extensions');
|
expect(track).toHaveProperty('extensions');
|
||||||
expect(track.extensions).toHaveProperty('line');
|
expect(track.extensions).toHaveProperty('gpx_style:line');
|
||||||
|
|
||||||
expect(track.extensions.line).toHaveProperty('color');
|
expect(track.extensions['gpx_style:line']).toHaveProperty('color');
|
||||||
expect(track.extensions.line).toHaveProperty('opacity');
|
expect(track.extensions['gpx_style:line']).toHaveProperty('opacity');
|
||||||
expect(track.extensions.line).toHaveProperty('weight');
|
expect(track.extensions['gpx_style:line']).toHaveProperty('weight');
|
||||||
|
|
||||||
expect(track.extensions.line.color).toBe("2d3ee9");
|
expect(track.extensions['gpx_style:line'].color).toBe("2d3ee9");
|
||||||
expect(track.extensions.line.opacity).toBe(0.5);
|
expect(track.extensions['gpx_style:line'].opacity).toBe(0.5);
|
||||||
expect(track.extensions.line.weight).toBe(5);
|
expect(track.extensions['gpx_style:line'].weight).toBe(5);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("Building", () => {
|
||||||
|
it("Simple", () => {
|
||||||
|
const path = "test-data/simple.gpx";
|
||||||
|
const data = fs.readFileSync(path, 'utf8');
|
||||||
|
const original = parseGPX(data);
|
||||||
|
|
||||||
|
const built = buildGPX(original);
|
||||||
|
const rebuilt = parseGPX(built);
|
||||||
|
|
||||||
|
expect(rebuilt).toEqual(original);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Multiple tracks", () => {
|
||||||
|
const path = "test-data/with_tracks.gpx";
|
||||||
|
const data = fs.readFileSync(path, 'utf8');
|
||||||
|
const original = parseGPX(data);
|
||||||
|
|
||||||
|
const built = buildGPX(original);
|
||||||
|
const rebuilt = parseGPX(built);
|
||||||
|
|
||||||
|
expect(rebuilt).toEqual(original);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Multiple segments", () => {
|
||||||
|
const path = "test-data/with_segments.gpx";
|
||||||
|
const data = fs.readFileSync(path, 'utf8');
|
||||||
|
const original = parseGPX(data);
|
||||||
|
|
||||||
|
const built = buildGPX(original);
|
||||||
|
const rebuilt = parseGPX(built);
|
||||||
|
|
||||||
|
expect(rebuilt).toEqual(original);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Waypoint", () => {
|
||||||
|
const path = "test-data/with_waypoint.gpx";
|
||||||
|
const data = fs.readFileSync(path, 'utf8');
|
||||||
|
const original = parseGPX(data);
|
||||||
|
|
||||||
|
const built = buildGPX(original);
|
||||||
|
const rebuilt = parseGPX(built);
|
||||||
|
|
||||||
|
expect(rebuilt).toEqual(original);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Time", () => {
|
||||||
|
const path = "test-data/with_time.gpx";
|
||||||
|
const data = fs.readFileSync(path, 'utf8');
|
||||||
|
const original = parseGPX(data);
|
||||||
|
|
||||||
|
const built = buildGPX(original);
|
||||||
|
const rebuilt = parseGPX(built);
|
||||||
|
|
||||||
|
expect(rebuilt).toEqual(original);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Heart rate", () => {
|
||||||
|
const path = "test-data/with_hr.gpx";
|
||||||
|
const data = fs.readFileSync(path, 'utf8');
|
||||||
|
const original = parseGPX(data);
|
||||||
|
|
||||||
|
const built = buildGPX(original);
|
||||||
|
const rebuilt = parseGPX(built);
|
||||||
|
|
||||||
|
expect(rebuilt).toEqual(original);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Cadence", () => {
|
||||||
|
const path = "test-data/with_cad.gpx";
|
||||||
|
const data = fs.readFileSync(path, 'utf8');
|
||||||
|
const original = parseGPX(data);
|
||||||
|
|
||||||
|
const built = buildGPX(original);
|
||||||
|
const rebuilt = parseGPX(built);
|
||||||
|
|
||||||
|
expect(rebuilt).toEqual(original);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Temperature", () => {
|
||||||
|
const path = "test-data/with_temp.gpx";
|
||||||
|
const data = fs.readFileSync(path, 'utf8');
|
||||||
|
const original = parseGPX(data);
|
||||||
|
|
||||||
|
const built = buildGPX(original);
|
||||||
|
const rebuilt = parseGPX(built);
|
||||||
|
|
||||||
|
expect(rebuilt).toEqual(original);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Power 1", () => {
|
||||||
|
const path = "test-data/with_power_1.gpx";
|
||||||
|
const data = fs.readFileSync(path, 'utf8');
|
||||||
|
const original = parseGPX(data);
|
||||||
|
|
||||||
|
const built = buildGPX(original);
|
||||||
|
const rebuilt = parseGPX(built);
|
||||||
|
|
||||||
|
expect(rebuilt).toEqual(original);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Power 2", () => {
|
||||||
|
const path = "test-data/with_power_2.gpx";
|
||||||
|
const data = fs.readFileSync(path, 'utf8');
|
||||||
|
const original = parseGPX(data);
|
||||||
|
|
||||||
|
const built = buildGPX(original);
|
||||||
|
const rebuilt = parseGPX(built);
|
||||||
|
|
||||||
|
expect(rebuilt).toEqual(original);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Surface", () => {
|
||||||
|
const path = "test-data/with_surface.gpx";
|
||||||
|
const data = fs.readFileSync(path, 'utf8');
|
||||||
|
const original = parseGPX(data);
|
||||||
|
|
||||||
|
const built = buildGPX(original);
|
||||||
|
const rebuilt = parseGPX(built);
|
||||||
|
|
||||||
|
expect(rebuilt).toEqual(original);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Track style", () => {
|
||||||
|
const path = "test-data/with_style.gpx";
|
||||||
|
const data = fs.readFileSync(path, 'utf8');
|
||||||
|
const original = parseGPX(data);
|
||||||
|
|
||||||
|
const built = buildGPX(original);
|
||||||
|
const rebuilt = parseGPX(built);
|
||||||
|
|
||||||
|
expect(rebuilt).toEqual(original);
|
||||||
});
|
});
|
||||||
});
|
});
|
Reference in New Issue
Block a user