Hi Gavin,
Finally, I could have a look at the flow again. Honestly, the most difficult part for me is to make sense of the data. After playing with the example file you provided my understanding is that a waypoint is a different set of data when compared with a tracking. It is true that they share a lot in common but there is a reason the GPX format defines different structures for each one. Said that I don´t get why you want (or need) to come up with a single resulting file. It makes sense for me (but I may be possibly wrong or missing something) to generate two separate files: one for waypoints and another one for tracks. There is a lot of information that is specific to each of them. I came up with a (simple) flow that will handle the gpx file and will generate two files. The data is extracted in many different ways to be flexible to modify the output for your needs. Hopefully, data extraction is now more robust. I added the distance calculation for each set of points in each track segment. For that purpose, I installed the NPM module haversine-distance. I share the flow. If you have specific questions on how to adjust the output format to your need please contact me in private in the forum.
Flow:
[{"id":"3115eb81.6c01f4","type":"tab","label":"GPX Parse - V2","disabled":false,"info":"Source:https://discourse.nodered.org/t/parse-gpx-file-and-extract-fields-from-javascript-object/7151/6\n\n"},{"id":"891d3776.11d948","type":"inject","z":"3115eb81.6c01f4","name":"Go","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":150,"y":160,"wires":[["f7def639.4fd288"]]},{"id":"e52422de.14b85","type":"change","z":"3115eb81.6c01f4","name":"Waypoint","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.gpx.wpt","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":180,"y":240,"wires":[["8dae91c3.a1b6"]]},{"id":"8dae91c3.a1b6","type":"split","z":"3115eb81.6c01f4","name":"Split0","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"topic","x":330,"y":240,"wires":[["ec1e9709.3c0248"]]},{"id":"ec1e9709.3c0248","type":"function","z":"3115eb81.6c01f4","name":"Format waypoint","func":"try {\n msg.pay = msg.payload;\n}\n\ncatch (err) {\n msg.timesort = \"added\";\n return msg;\n}\n\n\nmsg.timesort = msg.pay.time[0];\n\nlet {\n lat, \n lon} = msg.pay.$;\n\n\n\nlet {\n time,\n ele,\n name,\n src,\n magvar,\n geoidheight,\n cmt,\n desc,\n sym,\n type,\n fix,\n sat,\n hdop,\n vdop,\n pdop,\n ageofdgpsdata,\n dgpsid,\n extensions} = msg.pay;\n\ntry {\n //let link = msg.pay.link[0].$.href;\n msg.link = msg.pay.link[0].$.href;\n}\n\ncatch (error) {\n msg.link = \"empty link\";\n}\n\n\n// Select data to be added in the output string that will be saves to influxDB\n\nmsg.output = `Date: ${time}, Lat: ${lat}, Lon: ${lon}, Ele: ${ele} Name: ${name}, Source: ${src} Link: ${msg.link}`;\n//alternatively msg.out = [time, lat, lon, ele];\n\nnode.status({text:msg.parts.index});\nreturn msg;","outputs":1,"noerr":0,"x":480,"y":240,"wires":[["ee09f536.7c47a8"]]},{"id":"3970ccb2.488464","type":"change","z":"3115eb81.6c01f4","name":"Track","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.gpx.trk","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":190,"y":320,"wires":[["d78a0205.f0dc"]]},{"id":"d78a0205.f0dc","type":"split","z":"3115eb81.6c01f4","name":"Split1","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"topic","x":330,"y":320,"wires":[["607fcf1d.aa6df"]]},{"id":"607fcf1d.aa6df","type":"function","z":"3115eb81.6c01f4","name":"Format track","func":"var haversine = global.get('haversine_distance');\n\nfunction distance(arr) {\n let size = arr.length;\n let d = 0;\n for (let c=0; c < size-1; c++) {\n d = d + haversine(arr[c], arr[c+1]);\n }\nreturn d;\n}\n\n\ntry {\n msg.seg = msg.payload.trkseg[0];\n msg.trkpt = msg.payload.trkseg[0].trkpt[0];\n}\n\n\ncatch (err) {\n msg.timesort = \"added\";\n //node.warn(msg);\n return msg;\n}\n\n// trkseg may be empty - tag <trkseg></trkseg) or self closing <trkseg/>\n// results trkseg = [\"\"]; which is an array with oen element and content is an empty string\n// such case throw an error for the first line, not possible pay = \"\".trkpt[0]\n// the catch statement will inject a fake time into the msg part, so the sort node will not get lost\n \nmsg.timesort = msg.trkpt.time[0];\n\n/*\nlet {\n lat, \n lon} = msg.trkpt.$;\n \nlet {\n time,\n ele \n} = msg.trkpt;\n*/\n\n\nlet {\n name,\n type,\n cmt,\n desc,\n src,\n link,\n number,\n extensions} = msg.payload;\n \nmsg.segsize = msg.seg.trkpt.length;\nmsg.segdata = msg.seg.trkpt.map(ob => ({\"lat\": ob.$.lat, \"lon\":ob.$.lon, \"ele\":ob.ele[0], \"time\": ob.time[0]}));\nmsg.distance = distance(msg.segdata);\n\n// Select data to be added in the output string that will be saves to influxDB\nmsg.output = `Date: ${msg.timesort}, Segment: ${msg.parts.index}, ${msg.segsize} Points: , Type: ${type}, Distance: ${msg.distance}, Name: ${name}, Cmt: ${cmt}, Desc: ${desc}, Src: ${src}, Link: ${link}, Number: ${number}, Extensions: ${extensions}`;\n\nnode.status({text:msg.parts.index});\nreturn msg;\n","outputs":1,"noerr":0,"x":490,"y":320,"wires":[["1759ed0e.91ada3"]]},{"id":"8b02947a.630268","type":"file","z":"3115eb81.6c01f4","name":"Save track.csv","filename":"C:/users/OCM/.node-red/static/nrfiles/track.csv","appendNewline":true,"createDir":false,"overwriteFile":"false","x":1060,"y":340,"wires":[[]]},{"id":"f7def639.4fd288","type":"file in","z":"3115eb81.6c01f4","name":"Read gps-4.gpx","filename":"C:/users/OCM/.node-red/static/nrfiles/gps-4.gpx","format":"utf8","chunk":false,"sendError":false,"x":360,"y":160,"wires":[["59f65c4a.fa0a54"]]},{"id":"59f65c4a.fa0a54","type":"xml","z":"3115eb81.6c01f4","name":"","property":"payload","attr":"","chr":"","x":530,"y":160,"wires":[["7c4d356.17ac0cc"]]},{"id":"bc7e7224.f0a03","type":"comment","z":"3115eb81.6c01f4","name":"Parse GPX file format","info":"","x":140,"y":80,"wires":[]},{"id":"ba723cc0.3a4e3","type":"comment","z":"3115eb81.6c01f4","name":"waypoint","info":"<...\nlat=\"latitudeType [1] ?\"\nlon=\"longitudeType [1] ?\"> \n<ele> xsd:decimal </ele> [0..1] ?\n<time> xsd:dateTime </time> [0..1] ?\n<magvar> degreesType </magvar> [0..1] ?\n<geoidheight> xsd:decimal </geoidheight> [0..1] ?\n<name> xsd:string </name> [0..1] ?\n<cmt> xsd:string </cmt> [0..1] ?\n<desc> xsd:string </desc> [0..1] ?\n<src> xsd:string </src> [0..1] ?\n<link> linkType </link> [0..*] ?\n<sym> xsd:string </sym> [0..1] ?\n<type> xsd:string </type> [0..1] ?\n<fix> fixType </fix> [0..1] ?\n<sat> xsd:nonNegativeInteger </sat> [0..1] ?\n<hdop> xsd:decimal </hdop> [0..1] ?\n<vdop> xsd:decimal </vdop> [0..1] ?\n<pdop> xsd:decimal </pdop> [0..1] ?\n<ageofdgpsdata> xsd:decimal </ageofdgpsdata> [0..1] ?\n<dgpsid> dgpsStationType </dgpsid> [0..1] ?\n<extensions> extensionsType </extensions> [0..1] ?\n</...>","x":200,"y":460,"wires":[]},{"id":"dfb309b3.9ed4f8","type":"comment","z":"3115eb81.6c01f4","name":"trk","info":"<...> \n<name> xsd:string </name> [0..1] ?\n<cmt> xsd:string </cmt> [0..1] ?\n<desc> xsd:string </desc> [0..1] ?\n<src> xsd:string </src> [0..1] ?\n<link> linkType </link> [0..*] ?\n<number> xsd:nonNegativeInteger </number> [0..1] ?\n<type> xsd:string </type> [0..1] ?\n<extensions> extensionsType </extensions> [0..1] ?\n<trkseg> trksegType </trkseg> [0..*] ?\n</...>","x":350,"y":460,"wires":[]},{"id":"72f8342e.ff6fac","type":"link in","z":"3115eb81.6c01f4","name":"","links":["7c4d356.17ac0cc"],"x":55,"y":320,"wires":[["3970ccb2.488464"]]},{"id":"7c4d356.17ac0cc","type":"link out","z":"3115eb81.6c01f4","name":"","links":["72f8342e.ff6fac","baa07b7c.d62748"],"x":655,"y":160,"wires":[]},{"id":"ee09f536.7c47a8","type":"sort","z":"3115eb81.6c01f4","name":"","order":"ascending","as_num":false,"target":"","targetType":"seq","msgKey":"","msgKeyType":"elem","seqKey":"timesort","seqKeyType":"msg","x":650,"y":240,"wires":[["237e0f1d.688b8"]]},{"id":"1759ed0e.91ada3","type":"sort","z":"3115eb81.6c01f4","name":"","order":"ascending","as_num":false,"target":"","targetType":"seq","msgKey":"","msgKeyType":"elem","seqKey":"timesort","seqKeyType":"msg","x":650,"y":320,"wires":[["56fa664e.0368c8"]]},{"id":"fe7de72d.435cd8","type":"catch","z":"3115eb81.6c01f4","name":"","scope":null,"x":200,"y":400,"wires":[["20df0f94.d6032"]]},{"id":"20df0f94.d6032","type":"debug","z":"3115eb81.6c01f4","name":"","active":true,"tosidebar":true,"console":true,"tostatus":false,"complete":"true","targetType":"full","x":340,"y":400,"wires":[]},{"id":"10d6039d.d832ec","type":"switch","z":"3115eb81.6c01f4","name":"","property":"payload","propertyType":"msg","rules":[{"t":"istype","v":"undefined","vt":"undefined"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":910,"y":320,"wires":[[],["8b02947a.630268"]]},{"id":"100d284d.a115a8","type":"switch","z":"3115eb81.6c01f4","name":"","property":"output","propertyType":"msg","rules":[{"t":"istype","v":"undefined","vt":"undefined"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":910,"y":240,"wires":[[],["fcf6b70f.e257d8"]]},{"id":"56fa664e.0368c8","type":"change","z":"3115eb81.6c01f4","name":"Output","rules":[{"t":"set","p":"payload","pt":"msg","to":"output","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":770,"y":320,"wires":[["10d6039d.d832ec"]]},{"id":"baa07b7c.d62748","type":"link in","z":"3115eb81.6c01f4","name":"","links":["7c4d356.17ac0cc"],"x":55,"y":240,"wires":[["e52422de.14b85"]]},{"id":"237e0f1d.688b8","type":"change","z":"3115eb81.6c01f4","name":"Output","rules":[{"t":"set","p":"payload","pt":"msg","to":"output","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":770,"y":240,"wires":[["100d284d.a115a8"]]},{"id":"fcf6b70f.e257d8","type":"file","z":"3115eb81.6c01f4","name":"Save waypoint.csv","filename":"C:/users/OCM/.node-red/static/nrfiles/waypoint.csv","appendNewline":true,"createDir":false,"overwriteFile":"false","x":1070,"y":260,"wires":[[]]}]