I recently made some updates to it, so thought I share since I use my $YAML function a lot. Code is below, but example might be better.
More info on YAML is here:
https://yaml.org - which is actually written in valid YAML
YAML spec is here: https://yaml.org/spec/
If you have a complex array like this:
Code: Select all
:global myarray {
"system"=[/system resource print as-value];
"ipaddr"=[/ip address print as-value];
"iproutes"=[/ip route print as-value];
"ipconns"=[/ip firewall connection print as-value]}
and then try to ":put" it the console, you get the output below...noting that it's hard to read & and if you put that whole $myarray...impossible to read:
Code: Select all
:put ($myarray->"system")
architecture-name=arm;bad-blocks=0;board-name=RB1100AHx4 Dude Edition;build-time=Sep/13/2023 06:58:09;cpu=ARM;cpu-count=4;cpu-frequency=1400
;cpu-load=25;factory-software=6.41.3;free-hdd-space=70254592;free-memory=864948224;platform=Mikrotik;total-hdd-space=134479872;total-mem
ory=1073741824;uptime=1d02:15:38;version=7.12beta7 (development);write-sect-since-reboot=1791;write-sect-total=1624637
withe $YAML function below loaded, you can replace the :put with $YAML to get more readable output:
Code: Select all
$YAML ($myarray->"system")
architecture-name: arm
bad-blocks: 0
board-name: RB1100AHx4 Dude Edition
build-time: "Sep/13/2023 06:58:09"
cpu: ARM
cpu-count: 4
cpu-frequency: 1400
cpu-load: 25
factory-software: 6.41.3
free-hdd-space: 70254592
free-memory: 864948224
platform: Mikrotik
total-hdd-space: 134479872
total-memory: 1073741824
uptime: 1d02:15:38
version: 7.12beta7 (development)
write-sect-since-reboot: 1791
write-sect-total: 1624637
My $YAML function now supports a "file=", which wraps the more complex writing of large files inside the function (now it has to use another :global to support files, but no way to avoid...):
Code: Select all
$YAML $myarray file=sample-yaml
/file print where name~"sample-yaml"
Columns: NAME, TYPE, SIZE, CREATION-TIME
# NAME TYPE SIZE CREATION-TIME
0 sample-yaml.txt .txt file 54.5KiB 2023-09-14 09:17:01
And the same "pretty" output should be parsable in most programming editors, and parsable from most languages, using the above file.
$YAML function code
To use, add to scheduler at startup to load automatically.
Code: Select all
:global YAML
:global "temp-yaml-cache"
:set "temp-yaml-cache" [:toarray ""]
:set YAML do={
:global YAML
:local ar $1
:if ([:typeof $file]="str") do={
:local cacheid [:rndstr length=16 from=ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789]
:set ($"temp-yaml-cache"->"$cacheid") $ar
:execute file=$file script=":global YAML; \$YAML (\$\"temp-yaml-cache\"->\"$cacheid\"); :set (\$\"temp-yaml-cache\"->\"$cacheid\")"
:if ($console~"yes|1|true") do={} else={ :return [:nothing] }
}
:local lvl 0
:if ([:typeof $level]="num") do={:set lvl $level}
:local puttab do={
:local r ""
:if ($1=0) do={:return ""}
:for i from=1 to=$1 do={
:set $r "$r "
}
:return $r
}
:foreach k,v in=$ar do={
:local line
:if ([:typeof $v]="array") do={
:local arrmark "$k:"
:if ([:typeof "$k"]="num") do={:set arrmark "-"}
:set line ([$puttab $lvl] . $arrmark )
:put "$line"
:if ([:len $v]>0) do={
[$YAML $v level=($lvl+1)]
}
} else={
:local lv $v
:if (([:typeof $lv]="str")) do={
if ($lv~"[\\{\\}\\,\\*#\\\?|\\-\\<\\>\\!\\%@\\\\\\:\\&]") do={
:if ($lv~"[\"]") do={
:set lv "'$lv'"
} else={
:set lv "\"$lv\""
}
} else={
:if ($lv~"[']") do={
:set lv "\"$lv\""
} else={
:if ($lv~"[][]") do={
:set $lv "'$lv'"
} else={
:set lv $lv
}
}
}
:if ([:tostr $lv]="") do={:set lv "\"\""}
}
:if ([:typeof $k]="num") do={
:set line ([$puttab $lvl] . "- $[:tostr $lv]")
} else={
:set line ([$puttab $lvl] . "$[:tostr $k]: $[:tostr $lv]")
}
:put "$line"
}
}
:return [:nothing]
}
Implementation Notes:
- The string escaping pretty good, but not 100% (e.g. some strings may not get escaped properly). Script tries to leave strings UNQUOTED, since YAML allows that, and it's more readable. If needed, it should use " or '. There are corner cases where string escaping in $YAML isn't going to catch however.
- RouterOS "nil" should use "null" — $YAML takes the approach to make that an empty string. This was a stylist choice, since YAML's "null" everywhere made it look like a value was set.
- I'm told RouterOS v6 is dead, but other than [:rndstr] it should work on V6...
Comments, improvements, or suggestions are welcomed.