EFX expression syntax
EFX expressions are used to navigate, read and manipulate data inside eForms notice XML documents. Arguably, one does not need any language other than XPath in order to achieve the same goal. To understand why we had to move away from XPath follow this link. EFX expression syntax is, however, inspired by XPath and tries to simplify things and focus expressions on the specific domain of eForms.
Data types & literals
EFX uses the following data types:
- String
-
This is the equivalent of TEXT data type. String literals appear in single (
'
) or double ("
) quotes. There are several EFX expressions and functions that allow the manipulation of strings. - Number
-
EFX treats both integer and decimal numbers the same. The decimal separator is the dot (
.
). - Boolean
-
Boolean literals are
TRUE
andFALSE
. EFX also interprets the literalALWAYS
to meanTRUE
and the literalNEVER
to meanFALSE
. - Date, Time
-
In eForms, date and time are always stored in separate fields. Therefore there is no EFX data type that combines date and time together.
Date
andTime
are two separate data types. As eForms requires a time-zone to be specified for all date and time fields, EFX syntax requires date and time literals to include a time-zone.Unlike XPath, EFX date and time literals are not included in quotes. NOTE:
- Duration
-
In EFX, durations (a.k.a. measures), are similar to XPath durations. Duration literals use a similar syntax for example:
P3D
denotes "3 days".P3Y
stands for "3 years". Four different units are supported for duration measures: years (P1Y
), months (P1M
), weeks (P1W
) and days (P1D
).DayTimeDurationLiteral: '-'? 'P' INTEGER ('W' | 'D'); YearMonthDurationLiteral: '-'? 'P' INTEGER ('Y' | 'M');
Unlike XPath, finer granularity for durations in hours, minutes or seconds is not supported. In addition, measure units cannot be combined in one duration expression. For example you cannot write a duration of
P2Y3M
to denote a duration of two years and three months.Negative durations are also supported (e.g.
-P3W
is a valid negative duration of three weeks). Negative durations are useful in calculations.
Identifiers
EFX can recognise identifiers of eForms business terms, fields and nodes by taking advantage of the naming conventions used for them by the SDK. Codelist identifiers are included in parenthesis.
BtId: ('BT' | 'OPP' | 'OPT' | 'OPA') '-' [0-9]+;
FieldId: BtId ('(' (('BT' '-' [0-9]+) | [a-z]) ')')? ('-' ([a-zA-Z_] ([a-zA-Z_] | [0-9])*))+;
NodeId: 'ND' '-' [a-zA-Z0-9]+;
codelistReference: OpenParenthesis codelistId CloseParenthesis;
codelistId: Identifier;
Identifier: IdentifierPart ('-' IdentifierPart)*;
IdentifierPart: [a-zA-Z_] ([a-zA-Z_] | [0-9])*;
Variable: '$' IdentifierPart;
Referencing eForms fields and nodes
You can reference an eForms field in EFX by using its identifier. The same for referencing an eForms node.
This makes expressions simpler to read and write and also prevents us from having to change existing expressions if the schema changes in the future.
Just like in XPath, these references actually represent an XML node set
.
fieldReferenceWithPredicate: reference=fieldReferenceWithAxis (OpenBracket predicate CloseBracket)?;
fieldReferenceWithAxis: axis? simpleFieldReference;
simpleFieldReference: FieldId;
nodeReferenceWithPredicate: simpleNodeReference (OpenBracket predicate CloseBracket)?;
simpleNodeReference: NodeId;
BtId: ('BT' | 'OPP' | 'OPT' | 'OPA') '-' [0-9]+;
FieldId: BtId ('(' (('BT' '-' [0-9]+) | [a-z]) ')')? ('-' ([a-zA-Z_] ([a-zA-Z_] | [0-9])*))+;
NodeId: 'ND' '-' [a-zA-Z0-9]+;
Predicates
A field or node reference can be complemented with a predicate that restricts the XML elements
it matches.
As in XPath, EFX predicates are logical (boolean) EFX expressions included in square brackets.
predicate: booleanExpression;
Logical expressions
EFX supports boolean expressions including:
-
boolean literals (
TRUE
,FALSE
) -
comparisons (
==
,!=
,>
,>=
,<
,<=
) -
logical operations (
and
,or
,not
) -
regular expression pattern matching
-
checking for empty values
-
checking for presence of XML elements
-
checking for presence of values in lists
booleanExpression
: OpenParenthesis booleanExpression CloseParenthesis
| booleanExpression operator=Or booleanExpression
| booleanExpression operator=And booleanExpression
| stringExpression modifier=Not? In stringSequence
| booleanExpression modifier=Not? In booleanSequence
| numericExpression modifier=Not? In numericSequence
| dateExpression modifier=Not? In dateSequence
| timeExpression modifier=Not? In timeSequence
| durationExpression modifier=Not? In durationSequence
| stringExpression modifier=Not? Like pattern=STRING
| stringExpression Is modifier=Not? Empty
| pathFromReference Is modifier=Not? Present
| pathFromReference Is modifier=Not? Unique In absoluteFieldReference
| lateBoundExpression operator=Comparison lateBoundExpression
| booleanExpression operator=Comparison booleanExpression
| numericExpression operator=Comparison numericExpression
| stringExpression operator=Comparison stringExpression
| dateExpression operator=Comparison dateExpression
| timeExpression operator=Comparison timeExpression
| durationExpression operator=Comparison durationExpression
| If booleanExpression Then booleanExpression Else booleanExpression
| (Every | Some) iteratorList Satisfies booleanExpression
| booleanLiteral
| booleanFunction
| BooleanTypeCast lateBoundExpression
| lateBoundExpression
;
booleanLiteral: Always | True | Never | False;
booleanFunction
: Not OpenParenthesis booleanExpression CloseParenthesis
| ContainsFunction OpenParenthesis haystack=stringExpression Comma needle=stringExpression CloseParenthesis
| StartsWithFunction OpenParenthesis haystack=stringExpression Comma needle=stringExpression CloseParenthesis
| EndsWithFunction OpenParenthesis haystack=stringExpression Comma needle=stringExpression CloseParenthesis
| SequenceEqualFunction OpenParenthesis left=sequenceExpression Comma right=sequenceExpression CloseParenthesis
;
Comparison: '==' | '!=' | '>' | '>=' | '<' | '<=';
String expressions
EFX allows simple string manipulation.
stringExpression
: If booleanExpression Then stringExpression Else stringExpression
| stringLiteral
| stringFunction
| TextTypeCast lateBoundExpression
| lateBoundExpression
;
stringFunction
: SubstringFunction OpenParenthesis stringExpression Comma start=numericExpression (Comma length=numericExpression)? CloseParenthesis
| StringFunction OpenParenthesis numericExpression CloseParenthesis
| ConcatFunction OpenParenthesis stringExpression (Comma stringExpression)* CloseParenthesis
| FormatNumberFunction OpenParenthesis numericExpression (Comma format=stringExpression)? CloseParenthesis
;
Numeric expressions
EFX numbers can either be integers or decimals.
numericExpression
: OpenParenthesis numericExpression CloseParenthesis
| numericExpression operator=(Star | Slash | Percent) numericExpression
| numericExpression operator=(Plus | Minus) numericExpression
| If booleanExpression Then numericExpression Else numericExpression
| numericLiteral
| numericFunction
| NumericTypeCast lateBoundExpression
| lateBoundExpression
;
numericFunction
: CountFunction OpenParenthesis sequenceExpression CloseParenthesis
| NumberFunction OpenParenthesis stringExpression CloseParenthesis
| SumFunction OpenParenthesis numericSequence CloseParenthesis
| StringLengthFunction OpenParenthesis stringExpression CloseParenthesis
;
numericLiteral: INTEGER | DECIMAL;
INTEGER: '-'? [0-9]+;
DECIMAL: '-'? [0-9]? '.' [0-9]+;
Date, Time expressions
Date and time expressions allow the manipulation of date and time values.
dateExpression
: If booleanExpression Then dateExpression Else dateExpression
| dateLiteral
| dateFunction
| DateTypeCast lateBoundExpression
| lateBoundExpression
;
timeExpression
: If booleanExpression Then timeExpression Else timeExpression
| timeLiteral
| timeFunction
| TimeTypeCast lateBoundExpression
| lateBoundExpression
;
dateFunction
: DateFunction OpenParenthesis stringExpression CloseParenthesis
| AddMeasure OpenParenthesis dateExpression Comma durationExpression CloseParenthesis
| SubtractMeasure OpenParenthesis dateExpression Comma durationExpression CloseParenthesis
;
timeFunction
: TimeFunction OpenParenthesis stringExpression CloseParenthesis
;
// EFX tokens for date and time
DATE: DIGIT DIGIT DIGIT DIGIT '-' DIGIT DIGIT '-' DIGIT DIGIT (ZONE | 'Z');
TIME: DIGIT DIGIT Colon DIGIT DIGIT Colon DIGIT DIGIT (ZONE | 'Z');
ZONE: ('+' | '-') DIGIT DIGIT ':' DIGIT DIGIT;
Duration expressions
Duration expressions allow the manipulation of durations including:
-
Adding or subtracting a duration to/from another
-
Multiplying a duration by a number
-
Calculating the duration between two dates
durationExpression
: OpenParenthesis durationExpression CloseParenthesis
| endDate=dateExpression Minus startDate=dateExpression
| numericExpression Star durationExpression
| durationExpression Star numericExpression
| durationExpression Plus durationExpression
| durationExpression Minus durationExpression
| If booleanExpression Then durationExpression Else durationExpression
| durationLiteral
| durationFunction
| DurationTypeCast lateBoundExpression
| lateBoundExpression
;
durationFunction
: DayTimeDurationFunction OpenParenthesis stringExpression CloseParenthesis
| YearMonthDurationFunction OpenParenthesis stringExpression CloseParenthesis
;
Sequences and iterators
Sequences allow the manipulation of lists (sets of values).
sequenceExpression
: sequenceFromReference
| stringSequence
| booleanSequence
| numericSequence
| dateSequence
| timeSequence
| durationSequence
| sequenceFunction
;
sequenceFromReference
: fieldReference
| attributeReference
;
stringSequence
: OpenParenthesis stringExpression (Comma stringExpression)* CloseParenthesis
| stringSequenceFromIteration
| OpenParenthesis stringSequenceFromIteration CloseParenthesis
| codelistReference
| TextTypeCast? sequenceFromReference
;
codelistReference: OpenParenthesis codeListId=codelistId CloseParenthesis;
codelistId: Identifier;
// ... (1)
stringSequenceFromIteration: For iteratorList Return stringExpression; (2)
iteratorList: iteratorExpression (Comma iteratorExpression)*;
iteratorExpression: stringIteratorExpression | booleanIteratorExpression | numericIteratorExpression | dateIteratorExpression | timeIteratorExpression | durationIteratorExpression | contextIteratorExpression;
stringIteratorExpression: stringVariableDeclaration In stringSequence;
booleanIteratorExpression: booleanVariableDeclaration In booleanSequence;
numericIteratorExpression: numericVariableDeclaration In numericSequence;
dateIteratorExpression: dateVariableDeclaration In dateSequence;
timeIteratorExpression: timeVariableDeclaration In timeSequence;
durationIteratorExpression: durationVariableDeclaration In durationSequence;
contextIteratorExpression: contextVariableDeclaration In (fieldContext | nodeContext);
sequenceFunction
: DistinctValuesFunction OpenParenthesis (sequenceExpression | variableReference) CloseParenthesis
| UnionFunction OpenParenthesis (sequenceExpression | variableReference) Comma (sequenceExpression | variableReference) CloseParenthesis
| IntersectFunction OpenParenthesis (sequenceExpression | variableReference) Comma (sequenceExpression | variableReference) CloseParenthesis
| ExceptFunction OpenParenthesis (sequenceExpression | variableReference) Comma (sequenceExpression | variableReference) CloseParenthesis
;
1 | Several other sequence types are omitted here to make the excerpt short. See the EFX grammar for a complete specification. |
2 | For loops allow for the manipulation of sequences. Their syntax is very similar to for loops in XPath. |
See also: