Skip to content

Instantly share code, notes, and snippets.

@mike548141
Created February 12, 2024 06:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mike548141/ba1216c7dff8644c39d99ccc2887f6d6 to your computer and use it in GitHub Desktop.
Save mike548141/ba1216c7dff8644c39d99ccc2887f6d6 to your computer and use it in GitHub Desktop.
#
# Author: Mike Clements, Competitive Edge
# Version: 1.2-20240212
#
# Description:
# Takes a RouterOS array and outputs it as JSON (RFC8259).
#
# Pre-requisite:
#
# References:
# https://jsonformatter.curiousconcept.com/
#
# Inputs:
# array ($1)
# mandatory | array | n/a | The array to convert to JSON. RouterOS data types are mapped to JSON data types as follows
# + array - key/value associative array or multi-dimensional array;
# --> JSON object
# + array - ordered list of values that use the same data type;
# --> JSON array
# + bool (boolean) - values can bee true or false;
# --> JSON boolean
# + id (internal ID) - hexadecimal value prefixed by '*' sign. Each menu item has assigned unique number - internal ID;
# --> JSON string
# + ip - IP address;
# --> JSON string
# + ip-prefix - IP prefix;
# --> JSON string
# + ip6 - IPv6 address
# --> JSON string
# + ip6-prefix - IPv6 prefix
# --> JSON string
# + nil - default variable type if no value is assigned;
# --> JSON null
# + num (number) - 64bit signed integer, possible hexadecimal input;
# --> JSON number
# + str (string) - character sequence;
# --> JSON string
# + time - date and time value;
# --> JSON string
# output
# optional | string | json | json, json_pretty, yaml | Format of the data that is returned as the value of this function.
# verbose
# optional | integer | empty | 1, 2, 3 | Breaks the JSON standard but helps to diagnose issues including the source data type.
#
# Outputs:
# return
# mandatory | string | n/a | JSON data output.
#
:global fjson do={
:global fjsonwalker;
:local lparams {
"array"=$array;
"output"=$output;
"verbose"=$verbose
};
:local lresult;
# Parameter handler so you can pass the array content in without a prefix of array=
:if ([ :typeof $array; ] = "nothing") do={
:set ($lparams->"array") $1;
};
:if (($lparams->"verbose") >= 2) do={
:put "Input";
:put ($lparams->"array");
:put "\nOutput";
};
# Generate the JSON
:set lresult ("\7B" . [ $fjsonwalker array=($lparams->"array") verbose=($lparams->"verbose"); ] . "\7D");
# Output JSON
:if (($lparams->"verbose") >= 1) do={
:put $lresult;
};
:return $lresult;
};
:global fjsonwalker do={
:global fjsonwalker;
:local lcount;
:local lparams {
"array"=$array;
"verbose"=$verbose
};
:local lresult;
:foreach key,value in=($lparams->"array") do={
:set lcount ($lcount + 1);
:if ([ :typeof $value; ] = "array") do={
# Write the key as the name of the JSON object
:set lresult ($lresult . "\"" . $key . "\":\7B");
} else={
# Write the key
:set lresult ($lresult . "\"" . $key . "\":");
:if (([ :typeof $value; ] = "num") || ([ :typeof $value; ] = "bool")) do={
# Write number or boolean value as it is
:set lresult ($lresult . $value);
} else={
:if ([ :typeof $value; ] = "nil") do={
# Write nil values as a null
:set lresult ($lresult . "null");
} else={
# Write other values as a string
:set lresult ($lresult . "\"" . $value . "\"");
};
};
};
:if (($lparams->"verbose") >= 3) do={
:set lresult ($lresult . " # data type: " . [ :typeof $value; ] . ", length: " . [ :len $value; ]);
};
# If its not the last key/value then append a comma
:if (([ :typeof $value; ] != "array") && ($lcount < [ :len ($lparams->"array"); ])) do={
:set lresult ($lresult . ",");
};
:if ([ :typeof $value; ] = "array") do={
# Call self to process a nested array
:set lresult ($lresult . [ $fjsonwalker array=$value verbose=($lparams->"verbose"); ] . "\7D");
# If its not the last key/value then append a comma
:if ($lcount < [ :len ($lparams->"array"); ]) do={
:set lresult ($lresult . ",");
};
};
};
:return $lresult;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment