Format KML

This commit is contained in:
Norbert Renner 2021-04-01 11:53:17 +02:00
parent 7caa7aeba6
commit 00f2cead36
7 changed files with 246 additions and 77 deletions

View file

@ -82,9 +82,10 @@ BR.Export = L.Class.extend({
const turnInstructionMode = +this.profile.getProfileVar('turnInstructionMode');
const transportMode = this.profile.getTransportMode();
return BR.Gpx.format(track, turnInstructionMode, transportMode);
case 'kml':
return BR.Kml.format(track);
case 'geojson':
return JSON.stringify(track, null, 2);
case 'kml':
default:
break;
}

View file

@ -57,7 +57,7 @@ BR.Gpx = {
});
const statsComment = BR.Gpx._statsComment(geoJson);
gpx = '<?xml version="1.0" encoding="UTF-8"?>' + statsComment + gpxTransform.comment + gpx;
gpx = BR.Gpx.pretty(gpx);
gpx = BR.Xml.pretty(gpx);
return gpx;
},
@ -95,72 +95,4 @@ BR.Gpx = {
if (seconds != 0) time += seconds + 's';
return time;
},
// modified version of
// https://gist.github.com/sente/1083506#gistcomment-2254622
// MIT License, Copyright (c) 2016 Stuart Powers, ES6 version by Jonathan Gruber
pretty: function (xml, indentSize = 1) {
const PADDING = ' '.repeat(indentSize);
const newline = '\n';
// Remove all the newlines and then remove all the spaces between tags
xml = xml.replace(/>\s*(\r\n|\n|\r)\s*</gm, '><').replace(/>\s+</g, '><');
xml = xml.replace('<metadata/>', '');
// break into lines, keeping defined tags on a single line
const reg = /><(\/?)([\w!?][^ />]*)/g;
const singleLineTagList = ['trkpt', 'wpt'];
let lines = [];
let singleLineTag = null;
let startIndex = 0;
let match;
while ((match = reg.exec(xml)) !== null) {
const tag = match[2];
if (singleLineTag) {
if (singleLineTag === tag) {
singleLineTag = null;
}
} else {
if (singleLineTagList.includes(tag)) {
singleLineTag = tag;
}
let endIndex = match.index + 1;
lines.push(xml.substring(startIndex, endIndex));
startIndex = endIndex;
}
}
lines.push(xml.substring(startIndex));
// indent
const startTextEnd = /.+<\/\w[^>]*>$/;
const endTag = /^<\/\w/;
const startTag = /^<\w[^>]*[^\/]>.*$/;
let pad = 0;
lines = lines.map((node, index) => {
let indent = 0;
if (node.match(startTextEnd)) {
indent = 0;
} else if (node.match(endTag) && pad > 0) {
pad -= 1;
} else if (node.match(startTag)) {
indent = 1;
} else {
indent = 0;
}
pad += indent;
return PADDING.repeat(pad - indent) + node;
});
// break gpx attributes into separate lines
for (const [i, line] of lines.entries()) {
if (line.includes('<gpx ') && !line.includes(newline)) {
lines[i] = line.replace(/ (\w[^=" ]*=")/g, ` ${newline}${PADDING}$1`);
break;
}
}
return lines.join(newline);
},
};

7
js/format/Kml.js Normal file
View file

@ -0,0 +1,7 @@
BR.Kml = {
format: function (geoJson) {
// don't export properties as <ExtendedData>, probably no need for it
geoJson.features[0].properties = { name: geoJson.features[0].properties.name };
return BR.Xml.pretty(tokml(geoJson));
},
};

69
js/format/Xml.js Normal file
View file

@ -0,0 +1,69 @@
BR.Xml = {
// modified version of
// https://gist.github.com/sente/1083506#gistcomment-2254622
// MIT License, Copyright (c) 2016 Stuart Powers, ES6 version by Jonathan Gruber
pretty: function (xml, indentSize = 1) {
const PADDING = ' '.repeat(indentSize);
const newline = '\n';
// Remove all the newlines and then remove all the spaces between tags
xml = xml.replace(/>\s*(\r\n|\n|\r)\s*</gm, '><').replace(/>\s+</g, '><');
xml = xml.replace('<metadata/>', '');
// break into lines, keeping defined tags on a single line
const reg = /><(\/?)([\w!?][^ />]*)/g;
const singleLineTagList = ['trkpt', 'wpt'];
let lines = [];
let singleLineTag = null;
let startIndex = 0;
let match;
while ((match = reg.exec(xml)) !== null) {
const tag = match[2];
if (singleLineTag) {
if (singleLineTag === tag) {
singleLineTag = null;
}
} else {
if (singleLineTagList.includes(tag)) {
singleLineTag = tag;
}
let endIndex = match.index + 1;
lines.push(xml.substring(startIndex, endIndex));
startIndex = endIndex;
}
}
lines.push(xml.substring(startIndex));
// indent
const startTextEnd = /.+<\/\w[^>]*>$/;
const endTag = /^<\/\w/;
const startTag = /^<\w[^>]*[^\/]>.*$/;
let pad = 0;
lines = lines.map((node, index) => {
let indent = 0;
if (node.match(startTextEnd)) {
indent = 0;
} else if (node.match(endTag) && pad > 0) {
pad -= 1;
} else if (node.match(startTag)) {
indent = 1;
} else {
indent = 0;
}
pad += indent;
return PADDING.repeat(pad - indent) + node;
});
// break gpx attributes into separate lines
for (const [i, line] of lines.entries()) {
if (line.includes('<gpx ') && !line.includes(newline)) {
lines[i] = line.replace(/ (\w[^=" ]*=")/g, ` ${newline}${PADDING}$1`);
break;
}
}
return lines.join(newline);
},
};