Here's a bit of a fun challenge for anyone wanting to improve their JSONata Fu.
Take the output from the following nmap command output (change the IP address/subnet to match your own):
sudo nmap -sn --oX nmap.xml --privileged -R --system-dns --webxml 192.168.1.0/24
Then in Node-RED, read in the resulting XML file (nmap.xml
) and push through the XML node to turn it into JSON.
You will note that the conversion wraps XML attributes in $
properties that, in this case, are entirely unnecessary.
...
{
"status": [
{
"$": {
"state": "up",
"reason": "arp-response",
"reason_ttl": "0"
}
}
],
"address": [
{
"$": {
"addr": "192.168.1.167",
"addrtype": "ipv4"
}
},
{
"$": {
"addr": "B8:27:EB:DF:49:7E",
"addrtype": "mac",
"vendor": "Raspberry Pi Foundation"
}
}
],
"hostnames": [
{
"hostname": [
{
"$": {
"name": "pi2.knightnet.co.uk",
"type": "PTR"
}
}
]
}
],
"times": [
{
"$": {
"srtt": "406",
"rttvar": "5000",
"to": "100000"
}
}
]
},
...
So the challenge is to simplify the output, removing the extraneous $
properties:
{
"status": [
{
"state": "up",
"reason": "arp-response",
"reason_ttl": "0"
}
],
Good luck!
In case you are wondering what the end-game of this might be, I've two reasons. One is that the extraneous $
objects are common artefacts of converting from XML to JSON and so it isn't uncommon to want to get rid of them.
The second is that I am trying to automatically capture and update the devices on my network. I am combining this with some reference data that I maintain in an Excel spreadsheet detailing IP & MAC addresses with descriptions.
Ultimately, I will also combine this with 433MHz devices identified via my RFXtrx433E and devices on my Drayton Wiser smart heating system. Then I will have a complete picture of the devices I am interested in on my Home Automation system.
I will do a write-up of how to combine two arrays of objects using JSONata on my blog shortly which will hopefully be a useful reference for people trying to do similar tasks.
By the way, here is what I've come up with so far - but note that it just side-steps the challenge by building a new array of objects.
Spoiler
payload.nmaprun.host.(
{
/* Note different lookup methods */
"ip": address.*[addrtype="ipv4"].addr,
"mac": address.*[addrtype="mac"].addr.$uppercase(),
"vendor": address.*.vendor,
"hostname": hostnames.hostname."$".name,
/* srtt is in microseconds so convert to milliseconds. /1000 again to get to seconds */
"srtt": $parseInteger(times."$".srtt, '#0')/1000,
/* Add a JS timestamp for when this was run
* Eventually will use this to track last updates for devices. */
"timestamp": $parseInteger($$.payload.nmaprun."$".start, '#0')*1000
}
)
Note that the other thing I'd like to do to this is to turn the array into an object keyed on mac address.