# How to loop through json payload with Object of Objects and convert GPS points to GPX format?

**URL:** <https://discourse.nodered.org/t/how-to-loop-through-json-payload-with-object-of-objects-and-convert-gps-points-to-gpx-format/53557>\
**Category:** General\
**Created:** [11 November 2021 08:54 UTC](https://discourse.nodered.org/t/how-to-loop-through-json-payload-with-object-of-objects-and-convert-gps-points-to-gpx-format/53557 "2021-11-11T08:54:28Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![tjvandam](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/tjvandam/32/50838_2.png) [@tjvandam](https://discourse.nodered.org/u/tjvandam)\
**Post date:** [11 November 2021 08:54 UTC](https://discourse.nodered.org/t/how-to-loop-through-json-payload-with-object-of-objects-and-convert-gps-points-to-gpx-format/53557/1 "2021-11-11T08:54:28Z")

</div>

I am trying to convert a json payload that has a series of GPS location points and convert this payload into a GPX file format. The json payload is formatted as an Object of Objects. For this I need to loop through the Object of Objects and get specific values from it to put in the new GPX file format. However, I can't find the correct method to do this.

Format op json payload:

```auto
{
    "1": {
        "name": "msg_ublox_location",
        "data": {
            "latitude": 52.167908,
            "longitude": 5.129468,
            "altitude": 56.758,
            "success": true,
            "hot_retry": 0,
            "cold_retry": 0,
            "ttf": 0,
            "fix_type": 3,
            "siv": 9,
            "h_acc_est": 2,
            "pDOP": 2,
            "fix_time": 1636552316,
            "active_tracking": true,
            "cog": 18000,
            "sog": 0
        },
        "port": 2,
        "timestamp": 1636552317,
        "timestamp_parsed": "2021-11-10 14:51:57"
    },
    "2": {
        "name": "msg_ublox_location",
        "data": {
            "latitude": 52.167704,
            "longitude": 5.136292,
            "altitude": 50.814,
            "success": true,
            "hot_retry": 0,
            "cold_retry": 0,
            "ttf": 0,
            "fix_type": 3,
            "siv": 9,
            "h_acc_est": 3,
            "pDOP": 1,
            "fix_time": 1636552381,
            "active_tracking": true,
            "cog": 18000,
            "sog": 0
        },
        "port": 2,
        "timestamp": 1636552381,
        "timestamp_parsed": "2021-11-10 14:53:01"
    }
}

```

The output format I need to convert it to is GPX, and should look like this:

```auto
<?xml version="1.0" encoding="UTF-8"?>
<gpx version="1.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.topografix.com/GPX/1/0"
  xsi:schemaLocation="http://www.topografix.com/GPX/1/0
  http://www.topografix.com/GPX/1/0/gpx.xsd">
  <name>gpx file name</name>
  <trk><name>gpx track name</name><number>1</number><trkseg>
  <trkpt lat="52.167908" lon="5.129468"><ele>"56.758"</ele><time>"2021-11-10T13:51:56.000Z"</time></trkpt>
  <trkpt lat="52.167704" lon="5.136292"><ele>"50.814"</ele><time>"2021-11-10T13:53:01.000Z"</time></trkpt>
  </trkseg></trk>
</gpx>

```

I have tried to use the following function node, but it does not work:

```auto
var tracks_msgs = msg.payload; 
var xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +  
         "<gpx version=\"1.0\"\n" + 
         " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +  
         " xmlns=\"http://www.topografix.com/GPX/1/0\"\n" + 
         " xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0\n" + 
         " http://www.topografix.com/GPX/1/0/gpx.xsd\">\n"+ 
         " <name>gpx file name</name>\n" + 
         " <trk><name>gpx track name</name><number>1</number><trkseg>\n"; 
for (var i = 0; i < tracks_msgs.length; i++) { 
   xml += " <trkpt lat=\""+ tracks_msgs[i].data.latitude + 
          "\" lon=\"" + tracks_msgs[i].data.longitude + 
          "\"><ele>" + tracks_msgs[i].data.altitude + "</ele>" + 
          "<time>" + new Date(tracks_msgs[i].data.fix_time*1000).toISOString() + "</time></trkpt>\n"; 
} 
xml += " </trkseg></trk>\n</gpx>\n"; 
msg.payload = xml; 
return msg;

```

Can someone show me how to adapt this this function?

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [11 November 2021 10:08 UTC](https://discourse.nodered.org/t/how-to-loop-through-json-payload-with-object-of-objects-and-convert-gps-points-to-gpx-format/53557/2 "2021-11-11T10:08:30Z")

</div>

I normally loop through an object with something like this:

```auto
Object.keys(myObject).forEach( (element) => {
   // ...
})

```

It isn't the only way to do it but happens to be the one that I reach for first.

---

<div class="post-metadata">

**Author:** ![zenofmud](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/zenofmud/32/316_2.png) [@zenofmud](https://discourse.nodered.org/u/zenofmud)\
**Post date:** [11 November 2021 10:16 UTC](https://discourse.nodered.org/t/how-to-loop-through-json-payload-with-object-of-objects-and-convert-gps-points-to-gpx-format/53557/3 "2021-11-11T10:16:07Z")

</div>

Here is the start of how you could do it using some `template` nodes and a `for` loop in a `function` node. It builds the first couple parts ot the \<trkpt...\> and you will have to finish up the rest (good practice 😄)

```auto
[{"id":"fbcfa5b0f6b8398d","type":"inject","z":"a618aa32f05d2304","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":210,"y":120,"wires":[["0a223d97d977b5e3"]]},{"id":"0a223d97d977b5e3","type":"template","z":"a618aa32f05d2304","name":"Test data input","field":"payload","fieldType":"msg","format":"json","syntax":"mustache","template":"{\n \"1\": {\n \"name\": \"msg_ublox_location\",\n \"data\": {\n \"latitude\": 52.167908,\n \"longitude\": 5.129468,\n \"altitude\": 56.758,\n \"success\": true,\n \"hot_retry\": 0,\n \"cold_retry\": 0,\n \"ttf\": 0,\n \"fix_type\": 3,\n \"siv\": 9,\n \"h_acc_est\": 2,\n \"pDOP\": 2,\n \"fix_time\": 1636552316,\n \"active_tracking\": true,\n \"cog\": 18000,\n \"sog\": 0\n },\n \"port\": 2,\n \"timestamp\": 1636552317,\n \"timestamp_parsed\": \"2021-11-10 14:51:57\"\n },\n \"2\": {\n \"name\": \"msg_ublox_location\",\n \"data\": {\n \"latitude\": 52.167704,\n \"longitude\": 5.136292,\n \"altitude\": 50.814,\n \"success\": true,\n \"hot_retry\": 0,\n \"cold_retry\": 0,\n \"ttf\": 0,\n \"fix_type\": 3,\n \"siv\": 9,\n \"h_acc_est\": 3,\n \"pDOP\": 1,\n \"fix_time\": 1636552381,\n \"active_tracking\": true,\n \"cog\": 18000,\n \"sog\": 0\n },\n \"port\": 2,\n \"timestamp\": 1636552381,\n \"timestamp_parsed\": \"2021-11-10 14:53:01\"\n }\n}","output":"json","x":430,"y":120,"wires":[["5ae7e915433161f4","56605be699d85922"]]},{"id":"5ae7e915433161f4","type":"debug","z":"a618aa32f05d2304","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":610,"y":120,"wires":[]},{"id":"861d6c69a79e580d","type":"function","z":"a618aa32f05d2304","name":"","func":"let header = msg.header\nlet payload = msg.payload\nlet footer = msg.footer\nlet lat = ' '\nlet lon = ' '\nlet ele = ' '\nlet trkpt = ''\n\n//process each row and get the data bits\nfor (let row in payload) {\n lat = payload[row].data.latitude\n lon = payload[row].data.longitude\n ele = payload[row].data.altitude\n \n node.warn(\"processing \" + payload[row].data.latitude);\n\n// now build the <trkpt...> string\n trkpt = \"<trkpt lat=\\\"\" + lat + \"\\\" \"\n trkpt += \"lon=\\\"\" + lon\n trkpt += \"><ele>\\\"\" + ele + \"\\\"</ele>\"\n\n}\n\n// put the whole CML together\nmsg.payload = msg.header + trkpt + \"\\n\" + msg.footer\nreturn msg;\n\n// data string example\n// <trkpt lat=\"52.167908\" lon=\"5.129468\"><ele>\"56.758\"</ele><time>\"2021-11-10T13:51:56.000Z\"</time></trkpt>\n// <trkpt lat=\"52.167704\" lon=\"5.136292\"><ele>\"50.814\"</ele><time>\"2021-11-10T13:53:01.000Z\"</time></trkpt>\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":420,"y":300,"wires":[["09ce9117951a8c33"]]},{"id":"56605be699d85922","type":"template","z":"a618aa32f05d2304","name":"XML header","field":"header","fieldType":"msg","format":"text","syntax":"plain","template":"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<gpx version=\"1.0\"\n xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n xmlns=\"http://www.topografix.com/GPX/1/0\"\n xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0\n http://www.topografix.com/GPX/1/0/gpx.xsd\">\n <name>gpx file name</name>\n <trk><name>gpx track name</name><number>1</number><trkseg>\n","output":"str","x":430,"y":180,"wires":[["dc2dfc160d97c8db"]]},{"id":"dc2dfc160d97c8db","type":"template","z":"a618aa32f05d2304","name":"xml footer","field":"footer","fieldType":"msg","format":"text","syntax":"plain","template":" </trkseg></trk>\n</gpx>","output":"str","x":420,"y":240,"wires":[["861d6c69a79e580d"]]},{"id":"09ce9117951a8c33","type":"debug","z":"a618aa32f05d2304","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":610,"y":300,"wires":[]}]

```

---

<div class="post-metadata">

**Author:** ![bakman2](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bakman2/32/6207_2.png) [@bakman2](https://discourse.nodered.org/u/bakman2)\
**Post date:** [11 November 2021 10:18 UTC](https://discourse.nodered.org/t/how-to-loop-through-json-payload-with-object-of-objects-and-convert-gps-points-to-gpx-format/53557/4 "2021-11-11T10:18:30Z")

</div>

Like @TotallyInformation says - it is an object, not an array (as your function uses it).

```auto
const header = `<?xml version="1.0" encoding="UTF-8"?>
<gpx version="1.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns="http://www.topografix.com/GPX/1/0"
  xsi:schemaLocation="http://www.topografix.com/GPX/1/0
  http://www.topografix.com/GPX/1/0/gpx.xsd">
  <name>gpx file name</name>
  <trk><name>gpx track name</name><number>1</number><trkseg>`
const footer = `</trkseg></trk></gpx>`

let points = ""

for (const key of Object.keys(msg.payload)) {
    let pos = msg.payload[key].data
    
    points += `
    <trkpt lat="${pos.latitude}" lon="${pos.longitude}">
    <ele>${pos.altitude}</ele>
    <time>${new Date(pos.fix_time*1000).toISOString()}</time>
    </trkpt>`
}

msg.output = `${header}${points}${footer}`

return msg;

```

This creates an xml as your expected output.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [25 November 2021 10:18 UTC](https://discourse.nodered.org/t/how-to-loop-through-json-payload-with-object-of-objects-and-convert-gps-points-to-gpx-format/53557/5 "2021-11-25T10:18:58Z")

</div>

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.
