mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2025-09-04 01:22:32 +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";
|
||||
|
||||
export function parseGPX(gpxData: string): GPXFile {
|
||||
const parser = new XMLParser({
|
||||
ignoreAttributes: false,
|
||||
attributeNamePrefix: "",
|
||||
removeNSPrefix: true,
|
||||
attributesGroupName: 'attributes',
|
||||
isArray: (name: string) => {
|
||||
return name === 'trk' || name === 'trkseg' || name === 'trkpt' || name === 'wpt';
|
||||
},
|
||||
@@ -18,7 +18,7 @@ export function parseGPX(gpxData: string): GPXFile {
|
||||
transformTagName(tagName: string) {
|
||||
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
|
||||
return 'PowerExtension';
|
||||
return 'gpxpx:PowerExtension';
|
||||
}
|
||||
return tagName;
|
||||
},
|
||||
@@ -32,30 +32,69 @@ export function parseGPX(gpxData: string): GPXFile {
|
||||
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);
|
||||
}
|
||||
|
||||
if (tagName === 'PowerExtension') {
|
||||
if (tagName === 'gpxpx:PowerExtension') {
|
||||
// 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
|
||||
return {
|
||||
'PowerInWatts': parseFloat(tagValue)
|
||||
'gpxpx:PowerInWatts': parseFloat(tagValue)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return tagValue;
|
||||
},
|
||||
transformAttributeName(attributeName) {
|
||||
if (attributeName !== 'lat' && attributeName !== 'lon' && attributeName !== 'creator' && attributeName !== 'href') {
|
||||
return `@_${attributeName}`;
|
||||
}
|
||||
return attributeName;
|
||||
},
|
||||
});
|
||||
|
||||
const parsed = parser.parse(gpxData);
|
||||
|
||||
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 = {
|
||||
creator: string;
|
||||
attributes: GPXFileAttributes;
|
||||
metadata: Metadata;
|
||||
wpt: Waypoint[];
|
||||
trk: Track[];
|
||||
};
|
||||
|
||||
export type GPXFileAttributes = {
|
||||
creator: string;
|
||||
[key: string]: string;
|
||||
};
|
||||
|
||||
export type Metadata = {
|
||||
name?: string;
|
||||
desc?: string;
|
||||
@@ -14,14 +19,17 @@ export type Metadata = {
|
||||
};
|
||||
|
||||
export type Link = {
|
||||
href: string;
|
||||
attributes: LinkAttributes;
|
||||
text?: string;
|
||||
type?: string;
|
||||
};
|
||||
|
||||
export type LinkAttributes = {
|
||||
href: string;
|
||||
};
|
||||
|
||||
export type Waypoint = {
|
||||
lat: number;
|
||||
lon: number;
|
||||
attributes: Coordinates;
|
||||
ele?: number;
|
||||
time?: Date;
|
||||
name?: string;
|
||||
@@ -32,6 +40,11 @@ export type Waypoint = {
|
||||
type?: string;
|
||||
};
|
||||
|
||||
export type Coordinates = {
|
||||
lat: number;
|
||||
lon: number;
|
||||
};
|
||||
|
||||
export type Track = {
|
||||
name?: string;
|
||||
cmt?: string;
|
||||
@@ -44,7 +57,7 @@ export type Track = {
|
||||
};
|
||||
|
||||
export type TrackExtensions = {
|
||||
line?: LineStyleExtension;
|
||||
'gpx_style:line'?: LineStyleExtension;
|
||||
};
|
||||
|
||||
export type LineStyleExtension = {
|
||||
@@ -58,29 +71,28 @@ export type TrackSegment = {
|
||||
};
|
||||
|
||||
export type TrackPoint = {
|
||||
lat: number;
|
||||
lon: number;
|
||||
attributes: Coordinates;
|
||||
ele?: number;
|
||||
time?: Date;
|
||||
extensions?: TrackPointExtensions;
|
||||
};
|
||||
|
||||
export type TrackPointExtensions = {
|
||||
TrackPointExtension?: TrackPointExtension;
|
||||
PowerExtension?: PowerExtension;
|
||||
'gpxtpx:TrackPointExtension'?: TrackPointExtension;
|
||||
'gpxpx:PowerExtension'?: PowerExtension;
|
||||
};
|
||||
|
||||
export type TrackPointExtension = {
|
||||
hr?: number;
|
||||
cad?: number;
|
||||
atemp?: number;
|
||||
Extensions?: {
|
||||
'gpxtpx:hr'?: number;
|
||||
'gpxtpx:cad'?: number;
|
||||
'gpxtpx:atemp'?: number;
|
||||
'gpxtpx:Extensions'?: {
|
||||
surface?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export type PowerExtension = {
|
||||
PowerInWatts?: number;
|
||||
'gpxpx:PowerInWatts'?: number;
|
||||
}
|
||||
|
||||
export type Author = {
|
||||
|
Reference in New Issue
Block a user