The ExpressionParser is the part of Gentics Portal.Node that parses and interprets expressions, like rules (prules), datasource filters and assignment commands in reactions and the GeneralViewAction. See Section 8.2.13, “ExpressionParser Configuration” for detailed information about configuring the ExpressionParser and compatibility issues with older implementations.
This section describes the valid syntax for expressions. In general, there are two different types of expressions: assignments and rules.
Assignments are of the form [Name] [Assignment Operator] [Expression]
.
Examples for valid assigments are:
Assignment operators are used in Assignments and define how the lefthand-side property is to be modified.
An Expression is any legal combination of Operations, Constants, Literals, Names and Functions. Expressions may NOT contain Assignment Operators.
Rules are basically boolean Expressions (Expressions that evaluate to true
or false
) and can be used as rules for boolean settings or datasource filters.
Binary Operations define how operators (left hand side [lhs] operator and righ hand side [rhs] operator) shall be combined to calculate other values. The supported values of the operators and the generated value depend on the Operator and are listed below.
Table 4.162. Binary Operations
Operator | Supported operator types | Result type | Description |
---|---|---|---|
OR | boolean | boolean | Logical or: is true when at least one of the operands is true . Can also be written as || . |
AND | boolean | boolean | Logical and: is true when both operands are true . Can also be written as && . |
== | any | boolean | Equality comparison: is true when the operand values are equal. |
!= | any | boolean | Unequality comparison: is true when the operand values are not equal. |
> | numbers | boolean | "Greater" comparison: is true when the numerical value of the lhs operator is greater than the numerical value of the rhs operator. |
>= | numbers | boolean | "Greater or equal" comparison: is true when the numerical value of the lhs operator is greater or equal than the numerical value of the rhs operator. |
< | numbers | boolean | "Smaller" comparison: is true when the numerical value of the lhs operator is smaller than the numerical value of the rhs operator. |
<= | numbers | boolean | "Smaller or equal" comparison: is true when the numerical value of the lhs operator is smaller or equal than the numerical value of the rhs operator. |
LIKE | strings | boolean | "Like" operation: the result is true , when the rhs value matches the pattern of the lhs value. The rhs value might contain the character % as wildcard for any character sequence. |
CONTAINSONEOF | arrays | boolean | "Contains one of": the result is true , when the lhs values contain at least one of the values of the rhs array. |
CONTAINSNONE | arrays | boolean | "Contains none of": the result is true , when the lhs values contain none of the values of the rhs array. |
CONTAINSALL | arrays | boolean | "Contains all": the result is true , when the lhs values contain all of the values of the rhs array. Note: currently, this operator can only be used with static values (i.e. it is not possible to filter a datasource with a rule like "object.attribute CONTAINSALL ['a', 'b', 'c']") |
+ | numbers | number | "Summation" operation: the result is the sum of the operands values. |
- | numbers | number | "Subtraction" operation: the result is the difference of the operands values. |
* | numbers | number | "Multiplication" operation: the result is the product of the operands values. |
/ | numbers | number | "Division" operation: the result is the quotient of the operands values. This will fail when the rhs value is 0. |
% | numbers | number | "Modulus" operation: the result is the modulus of the integer division of the operands. This will fail when the rhs value is 0. |
There exist four types of literals: integer numbers, floating point numbers, strings and arrays.
Table 4.164. Literals
Type | Description |
---|---|
Integer | Integer literals can be notated in decimal form (starting with a number, but not with 0), in hexadecimal notation (starting with 0x ) or in octal notation (starting with 0 ). |
Floating Point Number | Floating point numbers can be given in the technical notation, including signs and exponents (see examples below). |
String | Strings have to be enclosed by " (double quotes) or ' (single quotes). The special characters enclosing character (double or single quote) and backslash (/ ) have to be escaped by backslash. Newline is written as \n and tabulator as \t . |
Array | Arrays are notated as [value1, value2, ...] , where the values may be literals (inluding nested arrays) or constants. |
Example 4.48. Examples of literals in expressions
42 (decimal integer) -99 (signed decimal integer) 0xff (hexadecimal integer, decimal value: 255) 010 (octal integer, decimal value: 8) -18.98e+1 (floating point integer, value: -189.8) 31.415926e-1 (floating point integer, value: 3.1415926) "Franz" (string literal) 'Sepp' (string literal) "\"'\n\t" (string literal, containing escaped characters) ["Franz", 42, true] (array) [['Sepp', 1.95], ['Franz', 1.84]] (nested arrays)
All character sequences that are not operators, literals, constants or
functions (see below) and for which the rules for Java identifiers apply,
are interpreted as names. Sequences of names that are only separated by
.
(dots) are interpreted as name-paths. When expression containing names are
evaluated, name-paths are resolved into their current values (which might be
null). Special name-paths starting with
object.
are interpreted as variables. When the expression is used as filter for
datasource queries, the variables are placeholders for attributes of the
filtered objects and their properties. For details on Java identifiers, see
the
Javadoc for Character.isJavaIdentifierPart()
.
Functions are Names followed by parenthesis
()
. Functions might have function parameters that can be Literals, Constants,
Name-paths, Functions or even Expressions.
Table 4.165. ExpressionParser functions
Name | Parameters | Result value | Description |
---|---|---|---|
concat(string, string, ...) | 2 or more | string | Concatenates the given strings. |
isempty(object) | 1 | boolean |
Returns
true
when the object's value is null, an empty string or an empty
Collection or Array.
|
subrule(attribute, subrule) | 2 | array |
This function can only be used in datasource filters for datasources of type contentrepository . It
generates a subquery and returns the given attribute from
all filtered objects. Note that for compatibility reasons,
the subrule must contain variables as
subobject
instead of
object
.
|
if(expression1, expression2[, expression3]) | 2 or 3 | any |
Evaluates
|
do(assignment1[, assignment2[, assignment3]...]) | 1 or more | assignment |
Performs all given assignments in the given order. This
function can be nested within the if() function to
perform a sequence of assignments, when the given
expression evaluates to
|
fromArray(array, index) | 2 | any |
Fetches the object with index
|
matches(object, expression) | 2 | boolean |
The matches() function implements a special kind of permission rule (for Gentics .Node ContentRepository datasource filters and evaluation). The function is used like:
Meaning: filter all objects that
matches at least one of the
given user permissions
(portal.user.permission).
because in this rule, it is not garantueed that the filtered object matches location and region for the SAME permissions object. |
eval(expression) | 1 | any |
The eval() function takes the given
expression, evaluates it and then
interprets the result as part of the
outer expression. This can for
example be used for expressions that
are configured in properties: The
expression
eval(portal.properties.rule)
would first resolve the property
portal.properties.rule
(e.g. to
portal.user.isloggedin
) and then evaluate this as rule.
|
insert(array, newobject[, index[, unique]]) | 2 - 4 | array |
The insert() function can be used to
insert an object to a given array
(or collection) at the specified
position. The optional parameter
index
defines the position where to insert
the
newobject
into the given
array
, where
0
would be the start and
-1
the end (which is the default). When
the parameter
unique
is set to
true
(default is
false
), the inserted object is removed
from the array first (if contained),
thus ensuring the uniqueness of the
object in the array. It is important
to notice, that this function does
not modify the
array
itself, but merely returns a copy
with the requested modifications
done.
|
get(object, attributeName) | 2 | any | The get method allows you to get a given attributeName from the object. This can be used, when the attributeName itself is not static, but is itself resolved or constructed by using functions. |
set(object, attributeName, value) | 3 | none | The set method allows you to set a given attributeName to a defined value for the given object. |
foreach(Map|Collection|array, iteratorName, loopBody) | 3 | list |
Allows you to iterate over a Map, Collection or array which is stored in a property named as 'iteratorName' within the 'loopBody'. (loopBody can be any other function call, e.g. do()). This function returns a list of all loopBody results. foreach(portal.pages, "page", page.reset = true)
|
echo(Object) | 1 | None | Similar to the EchoAction the echo function is only suitable for debugging - it will force a info log output containing string representation of the passed in value. |
i18n(string [,string]) | 1-2 | string | Translate the first parameter using the dictionary. The second parameter is optional and specifies the language id. If not specified the current language will be used. |
docallableaction("module Id", "view Id", "callable action id") | 3 | Boolean | Invokes the callable action with the given id which is defined in the given module id and view id. Returns true if action sequence was invoked successfully. See also Section 2.2.9, “Callable Actions” |
getContentID(datasource, pub_dir, filename, [node_id]) | 3-4 | String | Tries to convert the given input data (pub_dir, filename, optionally node_id) into the contentid by looking in the configured datasource. See also Section 4, “GenticsContentModule” for details on referencing content by pub_dir, filename and node_id. |
filter(rule, "postprocessorclass"[, data]) | 2-3 | Rule | The filter() function can only be used in datasource filters. When used it will create an instance of the class postprocessorclass and call the process() method with the objects that were returned by the rule . |
![]() | Tip |
---|---|
The |
Example 4.51. Example for conditional assignments
if(portal.user.isloggedin, data.value = "yes", data.value = "no") or data.value = if(portal.user.isloggedin, "yes", "no")
![]() | Warning |
---|---|
The |
![]() | Warning |
---|---|
The
|
![]() | Tip |
---|---|
The |
Example 4.52. Example for using the filter() function
Let's assume the following rule to get pages from a folder that match the user's permissions groups:
object.obj_type == 10007 AND object.folder_id = data.folder_id AND object.permgroups_view CONTAINSONEOF portal.user.groups
Since the attribute permgroups_view
is a multivalue attribute (and therefore not optimizable),
the resulting SQL statement will contain at least one join.
By moving the logic of filtering by permission groups into an instance of PostProcessor and using the filter()
function, the complex SQL statement can be avoided.
Example implementation of the PostProcessor
package com.example; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import com.gentics.api.lib.etc.ObjectTransformer; import com.gentics.api.lib.expressionparser.EvaluationException; import com.gentics.api.lib.expressionparser.ExpressionEvaluator; import com.gentics.api.lib.expressionparser.filtergenerator.PostProcessor; import com.gentics.api.lib.resolving.Resolvable; /** * Permission filter */ public class PermissionFilter implements PostProcessor { /** * Process the objects * @param resolvables collection of resolvables * @param data data object (containing the user permissions) */ public void process(List<Resolvable> resolvables, Object data) throws EvaluationException { // get the user permissions, which are provided to the filter() function Collection userPerms = ObjectTransformer.getCollection(data, Collections.EMPTY_LIST); // iterate over all resolvables for (Iterator<Resolvable> i = resolvables.iterator(); i.hasNext();) { Resolvable res = i.next(); // get the object permissions Collection objPerms = ObjectTransformer.getCollection( res.get("permgroups_view"), Collections.EMPTY_LIST); // filter out the objects with non-matching permissions if (!ExpressionEvaluator.containsOneOf(objPerms, userPerms)) { i.remove(); } } } }
Example usage
filter(object.obj_type == 10007 AND object.folder_id = data.folder_id, 'com.example.PermissionFilter', portal.user.groups)
The evaluation priority of different expression parts can be seen in the following table (operations with highest priority listed on top):
Constants, Literals, Names and Functions
Unary operations
Multiplicative calculation operations
Additive calculation operations
Comparison operations
Boolean operations
Assignments
Sequences of operations with the same priority level are evaluated from right to left. It is legal to use parenthesis within expressions to modify the evaluation order.