Skip to main content

AQL

This document was generated using AI assistance

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.

An AQL expression in the console, answered with the names of the elements the selected component points at

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.

SyntaxMeaning
expr.featureread 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.

OperatorsCategory
. ->feature navigation, operation call
notlogical negation
unary -arithmetic negation
* /multiplication, division
+ -addition, subtraction
< <= > >= = == <> !=comparison
andconjunction
ordisjunction
xorexclusive disjunction
impliesimplication

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

SyntaxTypeMeaning
42Integerinteger literal; a leading - is the negation operator
1.5Realreal literal; digits are required on both sides of the dot
'text'Stringstring literal; \' and \\ are the escapes
true, falseBooleanboolean literals
nullthe 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::businessan enumerationenumeration literal, written package, enumeration, value

Type syntax

A type is also an expression, so it can be passed as an argument.

SyntaxMeaning
String, Integer, Real, Booleanprimitive types
archimate::BusinessActora metaclass, qualified by its metamodel package
ecore::EObject, ecore::EClassEcore 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

SyntaxReturnsMeaning
a = b, a == bBooleanequality
a <> b, a != bBooleaninequality
v.oclIsKindOf(T)Booleanv is a T or a subtype of T
v.oclIsTypeOf(T)Booleanv is exactly a T
v.oclAsType(T)Tv seen as a T, so T's features are reachable
v.toString()Stringa string rendering of v
v + sStringv rendered as a string, concatenated with the string s - 42 + ' times' is '42 times'
v.lineSeparator()Stringthe platform line separator
v.trace()Stringa 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.

SyntaxReturnsMeaning
a < b, a.lessThan(b)Booleana is less than b
a <= b, a.lessThanEqual(b)Booleana is less than or equal to b
a > b, a.greaterThan(b)Booleana is greater than b
a >= b, a.greaterThanEqual(b)Booleana is greater than or equal to b

Boolean operations

Each operator is also callable by name.

SyntaxReturnsMeaning
a and b, a.and(b)Booleanconjunction
a or b, a.or(b)Booleandisjunction
a xor b, a.xor(b)Booleanexclusive disjunction
a implies b, a.implies(b)Booleantrue whenever a is false
not a, a.not()Booleannegation

String operations

Positions are 1-based, and substring bounds are inclusive.

SyntaxReturnsMeaning
s + t, s.concat(t)Stringconcatenation
s.size()Integernumber of characters
s.at(i)Stringthe character at position i - 'cat'.at(2) is 'a'
s.characters()Sequence(String)one entry per character
s.substring(lower)Stringfrom lower to the end - 'HelloWorld'.substring(6) is 'World'
s.substring(lower, upper)String'HelloWorld'.substring(1, 5) is 'Hello'
s.first(n)Stringthe first n characters, or all of them when s is shorter
s.last(n)Stringthe last n characters, or all of them when s is shorter
s.prefix(p)Strings with p put in front - 'World'.prefix('Hello') is 'HelloWorld'
s.contains(t), s.strstr(t)Booleant occurs in s
s.startsWith(t)Booleans begins with t
s.endsWith(t)Booleans ends with t
s.equalsIgnoreCase(t)Booleanequality, ignoring case
s.matches(regex)Booleanthe whole of s matches the regular expression
s.index(t)Integerposition of the first t, -1 when absent
s.index(t, from)Integerposition of the first t at or after from
s.lastIndex(t)Integerposition of the last t, -1 when absent
s.lastIndex(t, from)Integerposition of the last t searching backwards from from
s.strcmp(t)Integernegative, zero or positive as t sorts before, with or after s; upper case sorts before lower case
s.replace(regex, r)Stringreplace the first match of the regular expression
s.replaceFirst(regex, r)Stringreplace the first match of the regular expression
s.replaceAll(regex, r)Stringreplace every match of the regular expression
s.substitute(t, r)Stringreplace the first literal occurrence of t
s.substituteFirst(t, r)Stringreplace the first literal occurrence of t
s.substituteAll(t, r)Stringreplace every literal occurrence of t
s.toUpper()Stringevery character upper case
s.toLower()Stringevery character lower case
s.toUpperFirst()Stringthe first character upper case
s.toLowerFirst()Stringthe first character lower case
s.trim()Stringdrop leading and trailing whitespace
s.removeLineSeparators()Stringdrop every line separator
s.removeEmptyLines()Stringdrop every empty line
s.tokenize()Sequence(String)split on whitespace
s.tokenize(delimiter)Sequence(String)split on the given delimiter
s.isAlpha()Booleanevery character is a letter
s.isAlphaNum()Booleanevery character is a letter or a digit
s.toInteger()Integerparse as an integer
s.toReal()Realparse as a real
s.toBoolean()Booleanparse as a boolean

Number operations

Each of these applies to both Integer and Real.

SyntaxReturnsMeaning
a + bInteger, Realaddition
a - bInteger, Realsubtraction
a * bInteger, Realmultiplication
a / bInteger, Realdivision
-a, a.unaryMin()Integer, Realnegation
a.abs()Integer, Realabsolute value
a.floor()Integerthe integer part - 3.14.floor() is 3
a.round()Integerthe nearest integer - 3.14.round() is 3
a.min(b)Integer, Realthe smaller of the two
a.max(b)Integer, Realthe greater of the two
a.div(b)Integerthe integer quotient - 7.div(3) is 2
a.mod(b)Integerthe integer remainder - 7.mod(3) is 1
a.toInteger()Integeras an integer
a.toDouble()Realas a real
a.toLong()a long integeras a wider integer
a.toFloat()a single-precision realas 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.

SyntaxReturnsMeaning
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.

SyntaxReturnsMeaning
c->size()Integernumber of elements
c->isEmpty()Booleanthe collection has no element
c->notEmpty()Booleanthe collection has at least one element
c->first()Tthe first element
c->last()Tthe last element
c->at(i)Tthe element at position i
c->reverse()same kindthe elements in the opposite order
c->includes(v)Booleanv is an element
c->excludes(v)Booleanv is not an element
c->includesAll(other)Booleanevery element of other is an element of c
c->excludesAll(other)Booleanno element of other is an element of c
c->count(v)Integeroccurrences of v; on an ordered set, 0 or 1
c->indexOf(v)Integerposition of the first v
c->lastIndexOf(v)Integerposition of the last v
c->indexOfSlice(other)Integerposition where other first occurs as a run of elements
c->lastIndexOfSlice(other)Integerposition where other last occurs as a run of elements
c->startsWith(other)Booleanc begins with the elements of other
c->endsWith(other)Booleanc ends with the elements of other
c->sum()Integer, Realthe sum of the elements
c->min()Integer, Realthe smallest element
c->max()Integer, Realthe greatest element
c->including(v)same kindc with v added at the end
c->excluding(v)same kindc without v
c->append(v)same kindc with v added at the end
c->prepend(v)same kindc with v added at the front
c->insertAt(i, v)same kindc with v inserted at position i
c + other, c->add(other)same kindthe elements of both
c->concat(other)same kindthe elements of both
c - other, c->sub(other)same kindthe elements of c that are not in other
c->union(other)same kindthe elements of both, duplicates dropped
c->intersection(other)same kindthe elements present in both
c->drop(i)same kindthe elements after position i
c->dropRight(i)same kindthe 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 Tthe elements of a type, or of a set of types
c->sep(s)Sequences inserted between the elements
c->sep(prefix, s, suffix)Sequencethe same, wrapped in prefix and suffix
c->sep(prefix, s, suffix, ifEmpty)Sequencethe 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)
SyntaxReturnsMeaning
c->select(e | cond)same kindthe elements for which cond is true
c->reject(e | cond)same kindthe elements for which cond is false
c->collect(e | expr)same kindthe result of expr per element, flattened
c->any(e | cond)Tthe first element for which cond is true
c->exists(e | cond)Booleancond is true for at least one element
c->forAll(e | cond)Booleancond is true for every element
c->one(e | cond)Booleancond is true for exactly one element
c->isUnique(e | expr)Booleanexpr gives a different value for every element
c->sortedBy(e | key)same kindthe elements ordered by key
c->closure(e | expr)OrderedSetexpr 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

SyntaxReturnsMeaning
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()EObjectthe containing object
o.eContainer(T)Tthe nearest container of a type
o.eContainerOrSelf(T)To itself when it is a T, otherwise its nearest container of that type
o.eClass()EClassthe metaclass of o
o.eContainingFeature()EStructuralFeaturethe feature of the container that holds o
o.eContainmentFeature()EReferencethe containment reference that holds o
o.eGet(name)Objectthe value of a feature named by a string
o.eGet(feature)Objectthe value of a feature given as an object
o.eGet(feature, resolve)Objectthe 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

SyntaxReturnsMeaning
o.eResource()Resourcethe resource holding o
o.getURIFragment()Stringthe fragment identifying o within its resource
r.getURI()URIthe 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)EObjectthe object a fragment identifies
u.lastSegment()Stringthe last segment of a URI
u.fileExtension()Stringthe file extension of a URI
u.isPlatformResource()Booleanthe URI is a platform resource URI
u.isPlatformPlugin()Booleanthe URI is a platform plugin URI

Conditionals and bindings

SyntaxReturnsMeaning
if cond then a else b endifthe type of the branchesconditional; the else and the endif are both required
let n = expr in bodythe type of bodybind a name for the rest of the expression
let n : T = expr in bodythe type of bodythe same, with the type written out
let n = e1, m = e2 in bodythe type of bodybind several names at once
e | expra lambda, as taken by the iterators
e : T | expra 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:

SyntaxReturnsMeaning
o.getArchimateModel()ArchimateModelthe model the object belongs to
o.getArchimateConcept()ArchimateConceptthe concept a diagram object stands for
o.getDiagramModel()DiagramModelthe 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.

SyntaxBehaviour
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