AQL
Content may include inaccuracies, outdated information, or technical errors. Users are advised to cross-check critical information before implementation.
Acceleo Query Language is a query language over the model graph. It reads a model and never changes it, it is statically typed, and it offers content assist.

Writing an expression
An AQL expression is a single expression - there are no statements and no semicolons. It starts from a variable in scope and continues by navigation:
self.name
Feature navigation is a dot. Operations on collections use an arrow:
self.outgoingRelationships->size()
. applies to a single object, -> applies to a collection. Navigating a
multi-valued feature with . gives you a collection, which you then work on
with ->.
Both operators are forgiving in both directions. -> on a single value treats
it as a one-element collection, and on null as an empty one, so
self.name->size() is 0 when the name is unset. . on a collection applies
the navigation to each element and flattens the results, so
self.outgoingRelationships.target is the collection of targets.
Variables in scope
self is the object the expression is evaluated against, typed as its own
metaclass. Which object that is depends on where the expression runs - see
The expression console.
Because self is typed, content assist knows which features exist on it, and an
expression that navigates a feature the type does not have is flagged before it
runs.
In a document, self is the document itself and data is the sequence of
objects the document is built from. Every block that declares a variable adds it
to the scope of the expressions written inside that block, typed as the element
type of the block's own collection expression.
Types and type tests
Types are written with the metamodel prefix and a double colon:
archimate::ApplicationComponent. Enumeration values take a third segment:
archimate::FolderType::business.
oclIsKindOf(T) is true for the type and its subtypes, oclIsTypeOf(T) only
for the exact type, and oclAsType(T) narrows a value so the features of T
become reachable. On a collection, ->filter(T) keeps the elements of a type
and gives the result that element type.
Examples
Against ArchiMate, where self is an element:
The element carries a name:
self.name <> null and self.name.trim().size() > 0
The element is connected to something:
self.incomingRelationships->notEmpty() or self.outgoingRelationships->notEmpty()
Everything this element realizes:
self.outgoingRelationships
->select(r | r.oclIsKindOf(archimate::RealizationRelationship))
->collect(r | r.target)
The application components served by this one, sorted by name:
self.outgoingRelationships
->select(r | r.oclIsKindOf(archimate::ServingRelationship))
->collect(r | r.target)
->filter(archimate::ApplicationComponent)
->sortedBy(e | e.name)
Every element carries an owner property exactly once:
self.properties->select(p | p.key = 'owner')->size() = 1
Names follow a convention:
self.name.matches('[A-Z][A-Za-z ]*')
Against ArchiMate, where self is the model:
Every business process in the model:
self.eAllContents(archimate::BusinessProcess)
Elements that no relationship touches:
self.eAllContents(archimate::ArchimateElement)
->select(e | e.incomingRelationships->isEmpty()
and e.outgoingRelationships->isEmpty())
Duplicate names within the application layer:
self.eAllContents(archimate::ApplicationElement)
->select(e | self.eAllContents(archimate::ApplicationElement)
->select(o | o.name = e.name)->size() > 1)
The elements filed under the Business folder:
self.folders->select(f | f.type = archimate::FolderType::business)
->collect(f | f.elements)
Further reading
Acceleo Query Language documentation
Language reference
Expression form
A body is one expression. There are no statements, no assignment and no comment
syntax. let and the variables an iterator introduces are the only ways to name
a value.
| Syntax | Meaning |
|---|---|
expr.feature | read a structural feature |
expr.operation(args) | call an operation on a single value |
expr->operation(args) | call an operation on a collection |
(expr) | grouping |
Operands are evaluated before the operation runs, so both sides of an and or
an or are evaluated whatever the left side is worth. An if is the exception:
only the branch it takes is evaluated.
Where a result type is required, an expression whose inferred type does not match is reported before it runs.
Operator precedence
Highest first. Operators on the same row bind left to right.
| Operators | Category |
|---|---|
. -> | feature navigation, operation call |
not | logical negation |
unary - | arithmetic negation |
* / | multiplication, division |
+ - | addition, subtraction |
< <= > >= = == <> != | comparison |
and | conjunction |
or | disjunction |
xor | exclusive disjunction |
implies | implication |
and binds tighter than or, and or binds tighter than xor, so
true or true and false is true. An if ... endif and a let ... in are
self-contained operands.
Literals
| Syntax | Type | Meaning |
|---|---|---|
42 | Integer | integer literal; a leading - is the negation operator |
1.5 | Real | real literal; digits are required on both sides of the dot |
'text' | String | string literal; \' and \\ are the escapes |
true, false | Boolean | boolean literals |
null | the absent value | |
Sequence{1, 2, 3} | Sequence(T) | ordered, duplicates kept |
OrderedSet{1, 2} | OrderedSet(T) | ordered, duplicates dropped |
Sequence{}, OrderedSet{} | the empty collections | |
archimate::FolderType::business | an enumeration | enumeration literal, written package, enumeration, value |
Type syntax
A type is also an expression, so it can be passed as an argument.
| Syntax | Meaning |
|---|---|
String, Integer, Real, Boolean | primitive types |
archimate::BusinessActor | a metaclass, qualified by its metamodel package |
ecore::EObject, ecore::EClass | Ecore is always registered, so its types are always available |
Sequence(T) | a sequence type |
OrderedSet(T) | an ordered-set type |
{archimate::Node | archimate::Device} | a set of types, accepted wherever an operation takes several |
The multi-type overloads take a type-set form:
self.eAllContents({archimate::BusinessActor \| archimate::BusinessRole}).
Operations on any value
| Syntax | Returns | Meaning |
|---|---|---|
a = b, a == b | Boolean | equality |
a <> b, a != b | Boolean | inequality |
v.oclIsKindOf(T) | Boolean | v is a T or a subtype of T |
v.oclIsTypeOf(T) | Boolean | v is exactly a T |
v.oclAsType(T) | T | v seen as a T, so T's features are reachable |
v.toString() | String | a string rendering of v |
v + s | String | v rendered as a string, concatenated with the string s - 42 + ' times' is '42 times' |
v.lineSeparator() | String | the platform line separator |
v.trace() | String | a description of the metamodels and services the expression runs against |
Comparison operations
These apply to values with a natural order, which are the numbers and the strings.
| Syntax | Returns | Meaning |
|---|---|---|
a < b, a.lessThan(b) | Boolean | a is less than b |
a <= b, a.lessThanEqual(b) | Boolean | a is less than or equal to b |
a > b, a.greaterThan(b) | Boolean | a is greater than b |
a >= b, a.greaterThanEqual(b) | Boolean | a is greater than or equal to b |
Boolean operations
Each operator is also callable by name.
| Syntax | Returns | Meaning |
|---|---|---|
a and b, a.and(b) | Boolean | conjunction |
a or b, a.or(b) | Boolean | disjunction |
a xor b, a.xor(b) | Boolean | exclusive disjunction |
a implies b, a.implies(b) | Boolean | true whenever a is false |
not a, a.not() | Boolean | negation |
String operations
Positions are 1-based, and substring bounds are inclusive.
| Syntax | Returns | Meaning |
|---|---|---|
s + t, s.concat(t) | String | concatenation |
s.size() | Integer | number of characters |
s.at(i) | String | the character at position i - 'cat'.at(2) is 'a' |
s.characters() | Sequence(String) | one entry per character |
s.substring(lower) | String | from lower to the end - 'HelloWorld'.substring(6) is 'World' |
s.substring(lower, upper) | String | 'HelloWorld'.substring(1, 5) is 'Hello' |
s.first(n) | String | the first n characters, or all of them when s is shorter |
s.last(n) | String | the last n characters, or all of them when s is shorter |
s.prefix(p) | String | s with p put in front - 'World'.prefix('Hello') is 'HelloWorld' |
s.contains(t), s.strstr(t) | Boolean | t occurs in s |
s.startsWith(t) | Boolean | s begins with t |
s.endsWith(t) | Boolean | s ends with t |
s.equalsIgnoreCase(t) | Boolean | equality, ignoring case |
s.matches(regex) | Boolean | the whole of s matches the regular expression |
s.index(t) | Integer | position of the first t, -1 when absent |
s.index(t, from) | Integer | position of the first t at or after from |
s.lastIndex(t) | Integer | position of the last t, -1 when absent |
s.lastIndex(t, from) | Integer | position of the last t searching backwards from from |
s.strcmp(t) | Integer | negative, zero or positive as t sorts before, with or after s; upper case sorts before lower case |
s.replace(regex, r) | String | replace the first match of the regular expression |
s.replaceFirst(regex, r) | String | replace the first match of the regular expression |
s.replaceAll(regex, r) | String | replace every match of the regular expression |
s.substitute(t, r) | String | replace the first literal occurrence of t |
s.substituteFirst(t, r) | String | replace the first literal occurrence of t |
s.substituteAll(t, r) | String | replace every literal occurrence of t |
s.toUpper() | String | every character upper case |
s.toLower() | String | every character lower case |
s.toUpperFirst() | String | the first character upper case |
s.toLowerFirst() | String | the first character lower case |
s.trim() | String | drop leading and trailing whitespace |
s.removeLineSeparators() | String | drop every line separator |
s.removeEmptyLines() | String | drop every empty line |
s.tokenize() | Sequence(String) | split on whitespace |
s.tokenize(delimiter) | Sequence(String) | split on the given delimiter |
s.isAlpha() | Boolean | every character is a letter |
s.isAlphaNum() | Boolean | every character is a letter or a digit |
s.toInteger() | Integer | parse as an integer |
s.toReal() | Real | parse as a real |
s.toBoolean() | Boolean | parse as a boolean |
Number operations
Each of these applies to both Integer and Real.
| Syntax | Returns | Meaning |
|---|---|---|
a + b | Integer, Real | addition |
a - b | Integer, Real | subtraction |
a * b | Integer, Real | multiplication |
a / b | Integer, Real | division |
-a, a.unaryMin() | Integer, Real | negation |
a.abs() | Integer, Real | absolute value |
a.floor() | Integer | the integer part - 3.14.floor() is 3 |
a.round() | Integer | the nearest integer - 3.14.round() is 3 |
a.min(b) | Integer, Real | the smaller of the two |
a.max(b) | Integer, Real | the greater of the two |
a.div(b) | Integer | the integer quotient - 7.div(3) is 2 |
a.mod(b) | Integer | the integer remainder - 7.mod(3) is 1 |
a.toInteger() | Integer | as an integer |
a.toDouble() | Real | as a real |
a.toLong() | a long integer | as a wider integer |
a.toFloat() | a single-precision real | as a narrower real |
Integer and Real are the two number types the type syntax names. toLong
and toFloat return the wider integer and the narrower real that the runtime
distinguishes underneath them.
Collection kinds and conversions
There are two collection kinds. Sequence is ordered and keeps duplicates;
OrderedSet is ordered and drops them.
| Syntax | Returns | Meaning |
|---|---|---|
c->asSequence() | Sequence(T) | as a sequence, duplicates kept |
c->asSet() | OrderedSet(T) | as an ordered set, duplicates dropped |
c->asOrderedSet() | OrderedSet(T) | as an ordered set, duplicates dropped |
An operation that returns a collection returns the kind it received, so
->select on a sequence gives a sequence and on an ordered set gives an ordered
set.
Operations on collections
Indexes are 1-based.
| Syntax | Returns | Meaning |
|---|---|---|
c->size() | Integer | number of elements |
c->isEmpty() | Boolean | the collection has no element |
c->notEmpty() | Boolean | the collection has at least one element |
c->first() | T | the first element |
c->last() | T | the last element |
c->at(i) | T | the element at position i |
c->reverse() | same kind | the elements in the opposite order |
c->includes(v) | Boolean | v is an element |
c->excludes(v) | Boolean | v is not an element |
c->includesAll(other) | Boolean | every element of other is an element of c |
c->excludesAll(other) | Boolean | no element of other is an element of c |
c->count(v) | Integer | occurrences of v; on an ordered set, 0 or 1 |
c->indexOf(v) | Integer | position of the first v |
c->lastIndexOf(v) | Integer | position of the last v |
c->indexOfSlice(other) | Integer | position where other first occurs as a run of elements |
c->lastIndexOfSlice(other) | Integer | position where other last occurs as a run of elements |
c->startsWith(other) | Boolean | c begins with the elements of other |
c->endsWith(other) | Boolean | c ends with the elements of other |
c->sum() | Integer, Real | the sum of the elements |
c->min() | Integer, Real | the smallest element |
c->max() | Integer, Real | the greatest element |
c->including(v) | same kind | c with v added at the end |
c->excluding(v) | same kind | c without v |
c->append(v) | same kind | c with v added at the end |
c->prepend(v) | same kind | c with v added at the front |
c->insertAt(i, v) | same kind | c with v inserted at position i |
c + other, c->add(other) | same kind | the elements of both |
c->concat(other) | same kind | the elements of both |
c - other, c->sub(other) | same kind | the elements of c that are not in other |
c->union(other) | same kind | the elements of both, duplicates dropped |
c->intersection(other) | same kind | the elements present in both |
c->drop(i) | same kind | the elements after position i |
c->dropRight(i) | same kind | the elements before position i |
c->subSequence(from, to) | Sequence(T) | the elements from from to to, inclusive |
c->subOrderedSet(from, to) | OrderedSet(T) | the elements from from to to, inclusive |
c->filter(T) | collection of T | the elements of a type, or of a set of types |
c->sep(s) | Sequence | s inserted between the elements |
c->sep(prefix, s, suffix) | Sequence | the same, wrapped in prefix and suffix |
c->sep(prefix, s, suffix, ifEmpty) | Sequence | the same; ifEmpty is false to give an empty result for an empty c |
filter accepts a metaclass, a primitive type or a type set:
c->filter(archimate::Node), c->filter(String),
c->filter({archimate::Node \| archimate::Device}).
Iterators
An iterator takes a lambda, written as a variable name, a | and an expression.
The variable may carry a type:
self.eContents()->select(e : archimate::Node | e.name <> null)
| Syntax | Returns | Meaning |
|---|---|---|
c->select(e | cond) | same kind | the elements for which cond is true |
c->reject(e | cond) | same kind | the elements for which cond is false |
c->collect(e | expr) | same kind | the result of expr per element, flattened |
c->any(e | cond) | T | the first element for which cond is true |
c->exists(e | cond) | Boolean | cond is true for at least one element |
c->forAll(e | cond) | Boolean | cond is true for every element |
c->one(e | cond) | Boolean | cond is true for exactly one element |
c->isUnique(e | expr) | Boolean | expr gives a different value for every element |
c->sortedBy(e | key) | same kind | the elements ordered by key |
c->closure(e | expr) | OrderedSet | expr applied over and over until it yields nothing new |
closure walks a chain: self->closure(e | e.eContainer()) is the list of
containers up to the root.
Model navigation
| Syntax | Returns | Meaning |
|---|---|---|
o.eContents() | Sequence(EObject) | the objects directly contained in o |
o.eContents(T) | Sequence(T) | the same, of one type or of a type set |
o.eAllContents() | Sequence(EObject) | everything contained, at any depth |
o.eAllContents(T) | Sequence(T) | the same, of one type or of a type set |
o.eContainer() | EObject | the containing object |
o.eContainer(T) | T | the nearest container of a type |
o.eContainerOrSelf(T) | T | o itself when it is a T, otherwise its nearest container of that type |
o.eClass() | EClass | the metaclass of o |
o.eContainingFeature() | EStructuralFeature | the feature of the container that holds o |
o.eContainmentFeature() | EReference | the containment reference that holds o |
o.eGet(name) | Object | the value of a feature named by a string |
o.eGet(feature) | Object | the value of a feature given as an object |
o.eGet(feature, resolve) | Object | the same, resolve to false to leave proxies unresolved |
o.eCrossReferences() | Sequence(EObject) | the objects o references without containing them |
o.eInverse() | OrderedSet(EObject) | the objects that reference o |
o.eInverse(T) | OrderedSet(T) | the same, of one type |
o.eInverse('feature') | OrderedSet(EObject) | the objects that reference o through a named feature |
o.ancestors() | Sequence(EObject) | every container of o, nearest first |
o.ancestors(T) | Sequence(T) | the same, of one type or of a type set |
o.siblings() | Sequence(EObject) | the other objects in the same container |
o.siblings(T) | Sequence(T) | the same, of one type or of a type set |
o.precedingSiblings() | Sequence(EObject) | the siblings before o |
o.precedingSiblings(T) | Sequence(T) | the same, of one type or of a type set |
o.followingSiblings() | Sequence(EObject) | the siblings after o |
o.followingSiblings(T) | Sequence(T) | the same, of one type or of a type set |
eInverse reads the inverse references tracked for the whole project, so it
finds referencing objects in the project's other models too. It answers in the
console and in a document; in a validation rule and a quick fix it returns an
empty set. A check that has to look at what points at an object reaches it by
navigating a feature instead, as self.incomingRelationships does.
Resource operations
| Syntax | Returns | Meaning |
|---|---|---|
o.eResource() | Resource | the resource holding o |
o.getURIFragment() | String | the fragment identifying o within its resource |
r.getURI() | URI | the URI of a resource |
r.getContents() | Sequence(EObject) | the roots of a resource |
r.getContents(T) | Sequence(T) | the roots of a type |
r.getEObject(fragment) | EObject | the object a fragment identifies |
u.lastSegment() | String | the last segment of a URI |
u.fileExtension() | String | the file extension of a URI |
u.isPlatformResource() | Boolean | the URI is a platform resource URI |
u.isPlatformPlugin() | Boolean | the URI is a platform plugin URI |
Conditionals and bindings
| Syntax | Returns | Meaning |
|---|---|---|
if cond then a else b endif | the type of the branches | conditional; the else and the endif are both required |
let n = expr in body | the type of body | bind a name for the rest of the expression |
let n : T = expr in body | the type of body | the same, with the type written out |
let n = e1, m = e2 in body | the type of body | bind several names at once |
e | expr | a lambda, as taken by the iterators | |
e : T | expr | a lambda whose variable carries a type |
let named = self.eAllContents(archimate::ArchimateElement)
->select(e | e.name <> null)
in named->size()
Operations declared by a metamodel
The operations a metamodel declares on its own metaclasses are callable like any other. ArchiMate declares several, among them:
| Syntax | Returns | Meaning |
|---|---|---|
o.getArchimateModel() | ArchimateModel | the model the object belongs to |
o.getArchimateConcept() | ArchimateConcept | the concept a diagram object stands for |
o.getDiagramModel() | DiagramModel | the diagram a diagram object belongs to |
Content assist proposes these alongside the built-in operations, so the operations a given metaclass carries are visible at the cursor.
Operations that return nothing here
These are part of the language and parse cleanly, but they have nothing to read in this product.
| Syntax | Behaviour |
|---|---|
T.allInstances() | reports that no root provider is registered and yields an empty collection; reach every instance with eAllContents from the model root instead |
s.promptString(), s.promptInteger(), s.promptLong(), s.promptFloat(), s.promptDouble() | read from a terminal, which an expression running on the server does not have |
key.getProperty(), key.getProperty(args) | read a property set that is empty |