jsxd is a library to sanely work with nested data structures as jsx produces. The data structures can represent objects (key value lists) or arrays (lists). Be aware that keys in an object are ordered based on comparison and not on adding order.
- General
- Functions
Keys is the abstraction over the Path in the nested structure that jsxd uses to address a value, keys can be:
- a
integer
in the case of array addressing (be aware that we start at 0!) - a
binary
in case of object addressing, this may be a nested path in javascript'ish style asa.b[2].c
also starting with a array index such as<<"[1]">>
is valid and equivalent to a simple integer key as[1]
. - a list of
keys
when addressing a nested value
From list creates a valid jsdx object form a list. It transverses the structure, arrays are not changed but objects are sorted by key, duplicate keys are not deleted!
jsxd exports get/2
method to read data the parameters passed are a key or list of keys, it either returns {ok, <value>}
or undefined
.
Object = [{<<"a">>, 1}, {<<"b">>, [10, 20, 30]}].
{ok, 1} = jsxd:get(<<"a">>, Object).
{ok, 20} = jsxd:get([<<"b">>, 1], Object).
undefined = jsxd:get([<<"b">>, 1,2], Object).
get/3
is a get method with a default value, it will never not return undefined
or a {ok, _}
tuple but instead always a value, either the one found or the default provided.
Object = [{<<"a">>, 1}].
1 = jsxd:get(<<"a">>, 42, Object).
42 = jsxd:get([<<"b">>, 1,2], 42, Object).
Selects keys from an object, this does not work recursively, the first argument is a just of keys to keep, all other keys will be dropped.
Writing data works using the set/3 method, it follows the same rules for keys as get/2 does, in addition it will create nested objects based on the Path on the following rules:
- If the key is a non existing object
integer
it will create an array. - If the key is a non existing object
binary
it will create an object. - If an array index is given that isn't existing yet it will padded with
null
values.
[null, <<"value">>] = jsxd:set(1, <<"value">>, []).
[null, [{<<"key">>, <<"value">>}]] = jsxd:set([1, <<"key">>], <<"value">>, []).
[{<<"a">>, 1}, {<<"b">>, [10, 99, 30]}] = jsxd:set([<<"b">>, 1], 99, [{<<"a">>, 1}, {<<"b">>, [10, 20, 30]}]).
This function simply deletes data from a¯n object
Updating works the same as setting data with the difference that instead of a new value a function is defined. You can add a default value that gets set if the key is not found otherwise the object is returned unchanged.
[{<<"a">>, 1}, {<<"b">>, [10, 21, 30]}] = jsxd:update([<<"b">>, 1], fun(X) -> X+1 end, [{<<"a">>, 1}, {<<"b">>, [10, 20, 30]}]).
[{<<"a">>, 1}, {<<"b">>, [10, 20, 30]}] = jsxd:update([<<"b">>, 3], fun(X) -> X+1 end, [{<<"a">>, 1}, {<<"b">>, [10, 20, 30]}]).
[{<<"a">>, 1}, {<<"b">>, [10, 21, 30]}] = jsxd:update([<<"b">>, 1], fun(X) -> X+1 end, [{<<"a">>, 1}, {<<"b">>, [10, 20, 30]}]).
Append a value to an array defined by the key. If the array does not exist a new array at that path is created. If the object at the path is not an array an error is thrown.
The same as append just that it does add the new element at the start of the array, this is much more efficient since arryas are stored Lists. This means if you want to add to an array and don't care for order, use this.
Maps over an object. The mapping function gets two values, the first being the key (or index) and the second the value. Returned is the new value.
Folds over an object, in the way foldl
or foldr
does. Order isn't guaranteed in objects; so it uses foldl
internally. The fold function gets three arguments, the key or index, the value and the accumulator, it returns a new accumulator.
Merges two objects, different keys of both objects are combined. If a key exists in both objects the value of the second object is taken.˘
Merges two objects, different keys of both objects are combined. If a key exists in both objects the ConflictFn is called with three parameters, the key
, the value of the first object and the value of the second object.
This function threads an object through a list of changing functions, it's a simple utility function to help preventing huge chains of commands. The treated object is always entered as the last element of a call, valid calls are: