mapdata
Prototype: mapdata(interpretation, pattern, array_or_container)
Return type: data
Description: Returns a data container holding a JSON array. The
array is a map across each element of array_or_container
, modified by
a pattern
. The map is either collected literally when interpretation
is none
, or canonified when interpretation
is canonify
,
or parsed as JSON when interpretation
is json
, or collected from pattern
,
invoked as a program, when interpretation
is json_pipe
.
This function can accept many types of data parameters.
The $(this.k)
and $(this.v)
variables expand to the key and value
of the current element, similar to the way this
is available for
maplist
.
If the array or data container has two levels, you'll also be able to
use the $(this.k[1])
variable for the key at the second level. See
the example below for an illustration.
The order of the keys is not guaranteed. Use the sort()
function if
you need order in the resulting output.
Arguments:
interpretation
: one ofnone
canonify
json
json_pipe
pattern
:string
, in the range:.*
array_or_container
:string
, in the range:.*
Example:
body common control
{
bundlesequence => { "run" };
}
bundle agent run
{
vars:
"myarray[lookup][big]" string => "lookup big";
"myarray[lookup][small]" string => "lookup small";
# every item must parse as valid JSON when the interpretation is `json`
"mapa_json" data => mapdata("json", '{ "key": "$(this.k)", "key2": "$(this.k[1])", "value": "$(this.v)" }', myarray);
"mapa_json_str" string => format("%S", mapa_json);
# every item is just a string when the interpretation is `none`
"mapa_none" data => mapdata("none", 'key=$(this.k), level 2 key = $(this.k[1]), value=$(this.v)', myarray);
"mapa_none_str" string => format("%S", mapa_none);
"mycontainer" data => parsejson('
{
"top":
{
"x": 100,
"y": 200
}
}');
# every item must parse as valid JSON when the interpretation is `json`
"mapc_json" data => mapdata("json", '{ "key": "$(this.k)", "key2": "$(this.k[1])", "value": "$(this.v)" }', mycontainer);
"mapc_json_str" string => format("%S", mapc_json);
# every item is just a string when the interpretation is `none`
"mapc_none" data => mapdata("none", 'key=$(this.k), level 2 key = $(this.k[1]), value=$(this.v)', mycontainer);
"mapc_none_str" string => format("%S", mapc_none);
reports:
"mapdata/json on classic CFEngine array result: $(mapa_json_str)";
"mapdata/none on classic CFEngine array result: $(mapa_none_str)";
"mapdata/json on data container result: $(mapc_json_str)";
"mapdata/none on data container result: $(mapc_none_str)";
}
Output:
R: mapdata/json on classic CFEngine array result: [{"key":"lookup","key2":"small","value":"lookup small"},{"key":"lookup","key2":"big","value":"lookup big"}]
R: mapdata/none on classic CFEngine array result: ["key=lookup, level 2 key = small, value=lookup small","key=lookup, level 2 key = big, value=lookup big"]
R: mapdata/json on data container result: [{"key":"top","key2":"x","value":"100"},{"key":"top","key2":"y","value":"200"}]
R: mapdata/none on data container result: ["key=top, level 2 key = x, value=100","key=top, level 2 key = y, value=200"]
json_pipe
The json_pipe
interpretation is intended to work with programs that take JSON
as input and produce JSON as output. This is a standard tool convention in the
Unix world. See the example below for the typical usage.
jq has a powerful programming language that
fits the json_pipe
interpretation well. It will take JSON input and product
JSON output. Please read the jq manual and
cookbook to get a feel for the power of this tool. When available,
jq will offer tremendous data manipulation
power for advanced cases where the built-in CFEngine functions are not enough.
Example with json_pipe:
body common control
{
bundlesequence => { "run" };
}
bundle agent run
{
vars:
"tester" data => '{ "x": 100, "y": [ true, "a", "b" ] }';
# "jq ." returns the same thing that was passed in
"pipe_passthrough" data => mapdata("json_pipe", '$(def.jq) .', tester);
"pipe_passthrough_str" string => format("%S", pipe_passthrough);
# "jq .x" returns what was under x wrapped in an array: [100]
"pipe_justx" data => mapdata("json_pipe", '$(def.jq) .x', tester);
"pipe_justx_str" string => format("%S", pipe_justx);
# "jq .y" returns what was under y wrapped in an array: [[true,"a","b"]]
"pipe_justy" data => mapdata("json_pipe", '$(def.jq) .y', tester);
"pipe_justy_str" string => format("%S", pipe_justy);
# "jq .y[]" returns each entry under y *separately*: [true,"a","b"]
"pipe_yarray" data => mapdata("json_pipe", '$(def.jq) .y[]', tester);
"pipe_yarray_str" string => format("%S", pipe_yarray);
# "jq .z" returns null because the key "z" is missing: [null]
"pipe_justz" data => mapdata("json_pipe", '$(def.jq) .z', tester);
"pipe_justz_str" string => format("%S", pipe_justz);
# "jq" can do math too! and much more!
"pipe_jqmath" data => mapdata("json_pipe", '$(def.jq) 1+2+3', tester);
"pipe_jqmath_str" string => format("%S", pipe_jqmath);
reports:
"mapdata/json_pipe passthrough result: $(pipe_passthrough_str)";
"mapdata/json_pipe just x result: $(pipe_justx_str)";
"mapdata/json_pipe just y result: $(pipe_justy_str)";
"mapdata/json_pipe array under y result: $(pipe_yarray_str)";
"mapdata/json_pipe just z result: $(pipe_justz_str)";
"mapdata/json_pipe math expression result: $(pipe_jqmath_str)";
}
Output:
R: mapdata/json_pipe passthrough result: [{"x":100,"y":[true,"a","b"]}]
R: mapdata/json_pipe just x result: [100]
R: mapdata/json_pipe just y result: [[true,"a","b"]]
R: mapdata/json_pipe array under y result: [true,"a","b"]
R: mapdata/json_pipe just z result: [null]
R: mapdata/json_pipe math expression result: [6]
History: Was introduced in 3.7.0. canonify
mode was introduced in 3.9.0. The collecting function behavior was added in 3.9. The json_pipe
mode was added in 3.9.
See also: maplist()
, maparray()
, canonify()
, about collecting functions, and data
documentation.