-
Notifications
You must be signed in to change notification settings - Fork 12
Jxl primitives
JXL (JSON Transformation Language) is not really a language at all, but a representation of the abstract syntax trees that jtlc works with. The trees consist of typed nodes, or tags — Javascript objects with constructor and prototype that define compile()
method — and untyped nodes such as strings, numbers, arrays, object literals (or really any objects without compile()
method) and functions. The tags are accessible as plain (i.e. non-constructor) functions in the namespace dojox.jtlc.tags
and return instances of the respective typed nodes. The interpretation of untyped nodes is controlled by the dojox.jtlc.JXL
language definition object in the context of JXL.
acc( input )
Ensures that the value of its argument (usually a constant) is stored in a local variable (accumulator). Usually used as part of an aggregation construct such as:
expr( '$1+=_expression_', input_generator, acc(0) )
It is not an error to use acc()
in an iterative context but the tag will have no effect as the accumulator will be overwritten by the next iteration.
arg( index )
Returns one of the arguments passed into the evaluator of the template. While current()
defaults to iterating over arg(0)
, the two are not equivalent: arg()
is not a generator and should be enclosed in from()
to produce one. The argument of arg()
should be a numeric value (usually a constant).
bind( function [, input0 … inputN ] )
Evaluates the input0 … inputN arguments, then applies function to them. In the iterative context, input0 is treated as the generator, the rest of the arguments are evaluated only once. If the input arguments are omitted completely, bind()
assumes that the function should be applied to current()
.
current()
In a singleton context, returns the value of the current input. Current input defaults to the value of arg(0)
but may be temporarily reset to different objects in a sub-template enclosed in primitives such as each()
, group()
and setkey()
. In an iterative context, current()
serves as a generator of values from current input.
defined( [ input ] )
Serves as a filter passing only the defined values (that is, values whose typeof
is not equal to 'undefined'
) from the input. Should not be used outside of iterative contexts.
each( input0 [, input1 … inputN ] )
Performs nested iterations by evaluating its first argument with current input set to the value generated by the second argument and so on. Thus the rightmost argument forms the outermost iteration and the leftmost argument forms the innermost iteration. This primitive can only be used in iterative contexts and evaluates every one of its arguments in an iterative context of its own. Note that each()
does not nest sinks, only the iterations. In fact, its usual application is flattening hierarchies formed by nested arrays passed into the template.
expr( expression [, input0 … inputN ] )
Evaluates its input0 … inputN arguments, then evaluates the inline expression, substituting the values of the arguments for placeholders $
, $#
, $@
and $0
through $9
as follows:
$ |
The value of input0 in singleton contexts; the current value generated by input0 in iterative contexts. |
$0 |
The value of current() evaluated just before current iterative context, if any. Note that it is not necessarily the actual array iterated upon so $0[$#] is not at all guaranteed to produce the innermost generated value. |
$1 through $9
|
Values of input1 through input9, always evaluated in a singleton context. |
$# |
Only in iterative contexts: number of the current iteration. |
$@ |
The scope object, roughly equivalent to Javascript this . |
1 The value of this
passed into the top-level call to template evaluator function is guaranteed to be accessible through the scope object’s prototype chain.
If the expression contains no placeholder strings and begins with an identifier, expr()
assumes the identifier to be a property reference on the current input and prepends "$."
to it.
2 This rule is prone to misinterpretation in complex situations and will be changed to a more syntactically strict one (prepending $.
only to expressions consisting only of a sole identifier or an identifier followed by an argument list in parentheses) in a future version of the library.
If no input arguments are provided, the expression is evaluated with input0 equal to current input. Note that expr()
is similar to bind()
except that bind()
refers to a function outside of the template’s evaluator and expr()
injects Javascript code directly into the evaluator’s body.
from( input )
Evaluates the input argument as a singleton and generates values from the array or dictionary it returns as its result. In singleton contexts returns array arguments as is and converts dictionary arguments to arrays of property values (use keys()
to obtain arrays of keys or to iterate over them).
group( keys, body [, input ] )
Provides SQL-like grouping capability by evaluating its body over subsequences from input. The subsequences are established by evaluating the keys (either a single sub-template or an array of subtemplates, typically inline expressions) over each element of the sequence and comparing the results. The longest contiguous subsequence of generated values where keys are equal forms a group. The body is then evaluated with
current input set to the entire group. The group()
primitive can be used only in iterative contexts; it generates values returned by the body: one value per group.
Note that for the grouping to work properly the input sequence should already be ordered in respect to the keys so usually group()
is applied to the results produced by a query()
. However, the user is left free to group sorted sequences originating elsewhere. If input argument is omitted, current input is used.
iota( [ start, [ step, ] ] stop )
Generates a sequence of numbers beginning at start, incremented by step and not reaching or exceeding stop. If step is negative, the numbers are generated as long as they are greater than stop. If omitted, start defaults to 0 and step to 1.
In singleton contexts, iota()
returns an array containing the entire sequence.
keys( [ input ] )
Generates keys from the input: property names if input is an object, indices if it is an array. If input is omitted, current input is used. In a singleton context, returns the entire array of keys.
lambda( body )
Evaluates to a function, local to the current closure, that encapsulates body. Access to current input within body will refer to the argument passed into this function, whenever it is called. This is always a singleton and should not be used in a generator position.
last( [ input ] )
Serves as a special type of sink, returning only the last value generated by input. Usually used for aggregation purposes. If input is omitted, current input is used.
many( input )
Evaluates its input in an iterative context. If many() is used within an externally established iterative context it does nothing, otherwise it establishes one.
one( input )
Evaluates its input in a singleton context even when used within an externally established iterative context (in which case one()
effectively works as a generator returning a single value).
query( query [, input0 … inputN ] )
Executes a query over the specified inputs (each of the arguments input0_…_inputN is evaluated as a singleton). By default, the query is pre-compiled with dojox.json.query()
and the resulting evaluator is associated with the compiled template via a closure; changing the queryLanguage
setting allow the user to use a different query language implementation following the same paradigm.
3 Due to numerous deficiencies in both specification and implementation of dojox.json.query()
, an unspecified future version of the library will switch the default queryLanguage
to a native, improved implementation of the JSON Query language.
In iterative contexts, query()
works as a generator returning individual matches from the query. In singleton contexts query()
returns an array of results.
Using query()
without the input arguments applies it to current input.
quote( value )
Treats value as a literal even if it is a Javascript object, array or string, preventing its interpretation by JXL.
replace( format [, input ] )
Formats and returns its input by performing substitutions within the format string. By default, replace()
uses dojo.replace()
; user can change this behavior with replaceLanguage setting. If the input argument is omitted, replace()
works with current input.
scope( body, slots [, input ] )
Builds the new scope object $@
from the value of the slots dictionary delegating to the prior scope via prototype chain, then evaluates body within the new scope returning its value as the result. Both slots and body are evaluated with current input set to the value of input argument, if present.
At the moment, slots has to be an object literal without a generator: it cannot be an expression dynamically yielding a dictionary or use setkey()
. This limitation may be removed in future versions. While each slot may evaluate to any value whatsoever, it is recommended to use object-valued slots in order to allow side effects within body to work properly (Javascript always assigns new property values to the first object on the prototype chain even when the property value is modified with operations such as +=
or ++
).
extend( input )
By default, the new slot values hide the slots with the same names existing in current scope. The extend()
tag can be used to delegate from the new values to the old instead, by connecting their prototype chains appropriately. The tag itself does not modify the value in any way but serves to inform scope()
that the slot resulting from this value should delegate to the old slot value, if present.
setkey( body [, input ] )
Changes the key (property name) under which computed values are stored in a dictionary. The input argument is evaluated first, then body is evaluated as a singleton with current input set to the value returned by input; usually, the body consists of a replace()
, possibly in combination with expr()
. The result returned by the body is used as the key, the value from the input serves as the result of the setkey()
itself. The setkey()
primitive can be used both within singletons and iterative contexts, but makes little sense in the former. Without the input argument, setkey()
operates on the current input.
{ key0: input0 [, … keyN: inputN ] }
Object literals are sinks producing dictionaries (anonymous Javascript objects). By default, all inputs of an object literal are evaluated in singleton mode and the resulting values inserted into the resulting dictionary with literal key values. In order to populate a dictionary with keys generated from an input sequence, use the setkey()
primitive from a sub-template enclosed within many()
. In this case the key associated with this sub-template within the literal will be ignored and the computed value will be used instead.
[ input0 [, …inputN ] ]
Array literals are sinks producing anonymous Javascript arrays. By default, each input of an array literal is evaluated in an iterative context of its own. In order to evaluate a singleton sub-template and put its
value in an array, enclose the sub-template within one()
.
Note that array literals themselves are not generators and should not appear in an iterative context even though they establish an iterative context of their own inside the brackets. In order to use the value produced by an array literal as a generator, enclose it in from()
.
String literals may appear in place of a sub-template anywhere in JXL. They are interpreted differently depending on the context: in the context of a singleton, the string is taken to be an inline expression
as if it were enclosed in an expr()
tag. In an iterative context, the string is treated as if it was enclosed in query()
, i.e. as a query without additional parameters.
Numeric and boolean literals are always interpreted as if they were enclosed in quote()
. Consequently, they may not appear in an iterative context.
Values with the type of function
are treated as if they were enclosed in bind()
.