Перейти к основному содержимому

AQL

Этот документ был подготовлен при помощи ИИ

Текст может содержать неточности, устаревшие данные или технические ошибки. Пожалуйста, проверяйте критически важную информацию перед использованием.

Acceleo Query Language — язык запросов к графу модели. Он только читает модель и никогда её не изменяет, статически типизирован и поддерживает автодополнение.

Выражение на AQL в консоли и ответ на него: имена элементов, на которые указывает выбранный компонент

Как пишется выражение

Выражение на AQL всегда одиночное: здесь нет операторов и нет точек с запятой. Начинается оно с переменной, доступной в текущем контексте, и продолжается навигацией:

self.name

По характеристике переходят через точку, операции над коллекциями вызывают через стрелку:

self.outgoingRelationships->size()

. применяется к одиночному объекту, -> — к коллекции. Навигация по многозначной характеристике через . даёт коллекцию, с которой дальше работают через ->.

Оба оператора допускают и другой вид аргумента. -> считает одиночное значение коллекцией из одного элемента, а null — пустой коллекцией, поэтому при незаданном имени self.name->size() равно 0. . на коллекции переходит от каждого элемента и объединяет результаты, поэтому self.outgoingRelationships.target даёт коллекцию целевых объектов.

Видимые переменные

self — объект, на котором вычисляется выражение, типизированный своим собственным метаклассом. Какой это объект, зависит от того, где выражение выполняется, — см. Консоль выражений.

self типизирован, поэтому автодополнение знает его характеристики, а обращение к характеристике, которой у типа нет, помечается ещё до запуска.

В документе self — это сам документ, а data — последовательность объектов, из которых документ строится. Переменная, объявленная блоком, доступна выражениям внутри этого блока и получает тип элемента той коллекции, которую блок перебирает.

Типы и проверки типов

Типы записываются с префиксом метамодели и двойным двоеточием: archimate::ApplicationComponent. Значения перечислений состоят из трёх сегментов: archimate::FolderType::business.

oclIsKindOf(T) истинно для типа и его подтипов, oclIsTypeOf(T) — только для точного типа, а oclAsType(T) приводит значение к T и открывает доступ к характеристикам T. На коллекции ->filter(T) оставляет элементы заданного типа и даёт результат с этим типом элемента.

Примеры

Для ArchiMate, где self — элемент:

У элемента есть имя:

self.name <> null and self.name.trim().size() > 0

Элемент с чем-то связан:

self.incomingRelationships->notEmpty() or self.outgoingRelationships->notEmpty()

Всё, что реализует этот элемент:

self.outgoingRelationships
->select(r | r.oclIsKindOf(archimate::RealizationRelationship))
->collect(r | r.target)

Компоненты приложений, обслуживаемые данным компонентом, отсортированные по имени:

self.outgoingRelationships
->select(r | r.oclIsKindOf(archimate::ServingRelationship))
->collect(r | r.target)
->filter(archimate::ApplicationComponent)
->sortedBy(e | e.name)

У каждого элемента ровно одно свойство owner:

self.properties->select(p | p.key = 'owner')->size() = 1

Имена соответствуют соглашению:

self.name.matches('[A-Z][A-Za-z ]*')

Для ArchiMate, где self — модель:

Все бизнес-процессы модели:

self.eAllContents(archimate::BusinessProcess)

Элементы, которых не касается ни одна связь:

self.eAllContents(archimate::ArchimateElement)
->select(e | e.incomingRelationships->isEmpty()
and e.outgoingRelationships->isEmpty())

Повторяющиеся имена внутри слоя приложений:

self.eAllContents(archimate::ApplicationElement)
->select(e | self.eAllContents(archimate::ApplicationElement)
->select(o | o.name = e.name)->size() > 1)

Элементы, лежащие в папке Business:

self.folders->select(f | f.type = archimate::FolderType::business)
->collect(f | f.elements)

Дополнительные материалы

Документация Acceleo Query Language

Справочник по языку

Форма выражения

Тело всегда состоит из одного выражения. Здесь нет операторов, нет присваивания и нет синтаксиса комментариев. Дать значению имя можно только через let или через переменную итератора.

СинтаксисЗначение
expr.featureчтение структурной характеристики
expr.operation(args)вызов операции на одиночном значении
expr->operation(args)вызов операции на коллекции
(expr)группировка

Операнды вычисляются до выполнения операции: у and и or считаются обе стороны, какой бы ни оказалась левая. Исключение — if, где считается только выбранная ветвь.

Там, где требуется определённый тип результата, выражение с другим выведенным типом помечается ещё до запуска.

Приоритет операторов

От высшего к низшему. Операторы одной строки связываются слева направо.

ОператорыКатегория
. ->навигация по характеристике, вызов операции
notлогическое отрицание
унарный -арифметическое отрицание
* /умножение, деление
+ -сложение, вычитание
< <= > >= = == <> !=сравнение
andконъюнкция
orдизъюнкция
xorисключающая дизъюнкция
impliesимпликация

and связывает сильнее, чем or, а or — сильнее, чем xor, поэтому true or true and false равно true. Конструкции if ... endif и let ... in — самодостаточные операнды.

Литералы

СинтаксисТипЗначение
42Integerцелочисленный литерал; ведущий - — это оператор отрицания
1.5Realвещественный литерал; цифры обязательны по обе стороны точки
'text'Stringстроковый литерал; экранируются \' и \\
true, falseBooleanлогические литералы
nullотсутствующее значение
Sequence{1, 2, 3}Sequence(T)упорядоченная, дубликаты сохраняются
OrderedSet{1, 2}OrderedSet(T)упорядоченная, дубликаты отбрасываются
Sequence{}, OrderedSet{}пустые коллекции
archimate::FolderType::businessперечислениелитерал перечисления: пакет, перечисление, значение

Синтаксис типов

Тип — это тоже выражение, поэтому его можно передать как аргумент.

СинтаксисЗначение
String, Integer, Real, Booleanпримитивные типы
archimate::BusinessActorметакласс, уточнённый пакетом своей метамодели
ecore::EObject, ecore::EClassEcore зарегистрирована всегда, поэтому её типы доступны в любом выражении
Sequence(T)тип последовательности
OrderedSet(T)тип упорядоченного множества
{archimate::Node | archimate::Device}набор типов — там, где операция принимает несколько

Операции, принимающие несколько типов, понимают эту форму: self.eAllContents({archimate::BusinessActor \| archimate::BusinessRole}).

Операции над любым значением

СинтаксисВозвращаетЗначение
a = b, a == bBooleanравенство
a <> b, a != bBooleanнеравенство
v.oclIsKindOf(T)Booleanv — это T или подтип T
v.oclIsTypeOf(T)Booleanv — в точности T
v.oclAsType(T)Tv как T, с доступом к характеристикам T
v.toString()Stringстроковое представление v
v + sStringv, приведённое к строке и соединённое с s42 + ' times' даёт '42 times'
v.lineSeparator()Stringразделитель строк текущей платформы
v.trace()Stringописание метамоделей и сервисов, в контексте которых выполняется выражение

Операции сравнения

Применимы к числам и строкам — значениям с естественным порядком.

СинтаксисВозвращаетЗначение
a < b, a.lessThan(b)Booleana меньше b
a <= b, a.lessThanEqual(b)Booleana меньше b или равно ему
a > b, a.greaterThan(b)Booleana больше b
a >= b, a.greaterThanEqual(b)Booleana больше b или равно ему

Логические операции

Каждый оператор можно вызвать и по имени.

СинтаксисВозвращаетЗначение
a and b, a.and(b)Booleanконъюнкция
a or b, a.or(b)Booleanдизъюнкция
a xor b, a.xor(b)Booleanисключающая дизъюнкция
a implies b, a.implies(b)Booleanистина всегда, когда a ложно
not a, a.not()Booleanотрицание

Операции над строками

Позиции нумеруются с единицы; границы substring входят в результат.

СинтаксисВозвращаетЗначение
s + t, s.concat(t)Stringконкатенация
s.size()Integerчисло символов
s.at(i)Stringсимвол на позиции i'cat'.at(2) даёт 'a'
s.characters()Sequence(String)по одной записи на символ
s.substring(lower)Stringот lower до конца — 'HelloWorld'.substring(6) даёт 'World'
s.substring(lower, upper)String'HelloWorld'.substring(1, 5) даёт 'Hello'
s.first(n)Stringпервые n символов или все, если s короче
s.last(n)Stringпоследние n символов или все, если s короче
s.prefix(p)Strings с p впереди — 'World'.prefix('Hello') даёт 'HelloWorld'
s.contains(t), s.strstr(t)Booleant встречается в s
s.startsWith(t)Booleans начинается с t
s.endsWith(t)Booleans заканчивается на t
s.equalsIgnoreCase(t)Booleanравенство без учёта регистра
s.matches(regex)Booleanвся строка s соответствует регулярному выражению
s.index(t)Integerпозиция первого t, -1 при отсутствии
s.index(t, from)Integerпозиция первого t начиная с from
s.lastIndex(t)Integerпозиция последнего t, -1 при отсутствии
s.lastIndex(t, from)Integerпозиция последнего t при поиске назад от from
s.strcmp(t)Integerотрицательное, ноль или положительное — t идёт до s, совпадает с ним или идёт после; верхний регистр сортируется раньше нижнего
s.replace(regex, r)Stringзаменить первое совпадение с регулярным выражением
s.replaceFirst(regex, r)Stringзаменить первое совпадение с регулярным выражением
s.replaceAll(regex, r)Stringзаменить все совпадения с регулярным выражением
s.substitute(t, r)Stringзаменить первое буквальное вхождение t
s.substituteFirst(t, r)Stringзаменить первое буквальное вхождение t
s.substituteAll(t, r)Stringзаменить все буквальные вхождения t
s.toUpper()Stringвсе символы в верхнем регистре
s.toLower()Stringвсе символы в нижнем регистре
s.toUpperFirst()Stringпервый символ в верхнем регистре
s.toLowerFirst()Stringпервый символ в нижнем регистре
s.trim()Stringубрать пробельные символы в начале и в конце
s.removeLineSeparators()Stringубрать все разделители строк
s.removeEmptyLines()Stringубрать все пустые строки
s.tokenize()Sequence(String)разбить по пробельным символам
s.tokenize(delimiter)Sequence(String)разбить по заданному разделителю
s.isAlpha()Booleanвсе символы — буквы
s.isAlphaNum()Booleanвсе символы — буквы или цифры
s.toInteger()Integerразобрать как целое число
s.toReal()Realразобрать как вещественное число
s.toBoolean()Booleanразобрать как логическое значение

Операции над числами

Каждая из них применима и к Integer, и к Real.

СинтаксисВозвращаетЗначение
a + bInteger, Realсложение
a - bInteger, Realвычитание
a * bInteger, Realумножение
a / bInteger, Realделение
-a, a.unaryMin()Integer, Realотрицание
a.abs()Integer, Realмодуль
a.floor()Integerцелая часть — 3.14.floor() даёт 3
a.round()Integerближайшее целое — 3.14.round() даёт 3
a.min(b)Integer, Realменьшее из двух
a.max(b)Integer, Realбольшее из двух
a.div(b)Integerцелочисленное частное — 7.div(3) даёт 2
a.mod(b)Integerцелочисленный остаток — 7.mod(3) даёт 1
a.toInteger()Integerкак целое число
a.toDouble()Realкак вещественное число
a.toLong()длинное целоекак более широкое целое
a.toFloat()вещественное одинарной точностикак более узкое вещественное

Синтаксис типов знает только Integer и Real. toLong и toFloat дают более широкое целое и более узкое вещественное — их исполняющая среда различает внутри себя.

Виды коллекций и преобразования

Видов коллекций два. Sequence упорядочена и сохраняет дубликаты, OrderedSet упорядочена и отбрасывает их.

СинтаксисВозвращаетЗначение
c->asSequence()Sequence(T)как последовательность, дубликаты сохраняются
c->asSet()OrderedSet(T)как упорядоченное множество, дубликаты отбрасываются
c->asOrderedSet()OrderedSet(T)как упорядоченное множество, дубликаты отбрасываются

Операция над коллекцией сохраняет её вид: ->select на последовательности даёт последовательность, а на упорядоченном множестве — упорядоченное множество.

Операции над коллекциями

Индексы нумеруются с единицы.

СинтаксисВозвращаетЗначение
c->size()Integerчисло элементов
c->isEmpty()Booleanнет ни одного элемента
c->notEmpty()Booleanесть хотя бы один элемент
c->first()Tпервый элемент
c->last()Tпоследний элемент
c->at(i)Tэлемент на позиции i
c->reverse()тот же видэлементы в обратном порядке
c->includes(v)Booleanv входит в c
c->excludes(v)Booleanv не входит в c
c->includesAll(other)Booleanвсе элементы other входят в c
c->excludesAll(other)Booleanни один элемент other не входит в c
c->count(v)Integerчисло вхождений v; в упорядоченном множестве 0 или 1
c->indexOf(v)Integerпозиция первого v
c->lastIndexOf(v)Integerпозиция последнего v
c->indexOfSlice(other)Integerпозиция первого вхождения other подряд идущим отрезком
c->lastIndexOfSlice(other)Integerпозиция последнего вхождения other подряд идущим отрезком
c->startsWith(other)Booleanc начинается с элементов other
c->endsWith(other)Booleanc заканчивается элементами other
c->sum()Integer, Realсумма элементов
c->min()Integer, Realнаименьший элемент
c->max()Integer, Realнаибольший элемент
c->including(v)тот же видc с добавленным в конец v
c->excluding(v)тот же видc без v
c->append(v)тот же видc с добавленным в конец v
c->prepend(v)тот же видc с добавленным в начало v
c->insertAt(i, v)тот же видc с v, вставленным на позицию i
c + other, c->add(other)тот же видэлементы обеих коллекций
c->concat(other)тот же видэлементы обеих коллекций
c - other, c->sub(other)тот же видэлементы c, которых нет в other
c->union(other)тот же видэлементы обеих коллекций, дубликаты отбрасываются
c->intersection(other)тот же видэлементы, входящие в обе коллекции
c->drop(i)тот же видэлементы после позиции i
c->dropRight(i)тот же видэлементы до позиции i
c->subSequence(from, to)Sequence(T)элементы с from по to включительно
c->subOrderedSet(from, to)OrderedSet(T)элементы с from по to включительно
c->filter(T)коллекция Tэлементы заданного типа или набора типов
c->sep(s)Sequences, вставленное между элементами
c->sep(prefix, s, suffix)Sequenceто же самое, обёрнутое в prefix и suffix
c->sep(prefix, s, suffix, ifEmpty)Sequenceто же самое; ifEmpty, равное false, даёт пустой результат для пустой c

filter принимает метакласс, примитивный тип или набор типов: c->filter(archimate::Node), c->filter(String), c->filter({archimate::Node \| archimate::Device}).

Итераторы

Итератор принимает лямбду, которая записывается как имя переменной, | и выражение. Переменной можно указать тип:

self.eContents()->select(e : archimate::Node | e.name <> null)
СинтаксисВозвращаетЗначение
c->select(e | cond)тот же видэлементы, для которых cond истинно
c->reject(e | cond)тот же видэлементы, для которых cond ложно
c->collect(e | expr)тот же видрезультат expr для каждого элемента, объединённый в одну коллекцию
c->any(e | cond)Tпервый элемент, для которого cond истинно
c->exists(e | cond)Booleancond истинно хотя бы для одного элемента
c->forAll(e | cond)Booleancond истинно для каждого элемента
c->one(e | cond)Booleancond истинно ровно для одного элемента
c->isUnique(e | expr)Booleanexpr даёт разное значение для каждого элемента
c->sortedBy(e | key)тот же видэлементы, упорядоченные по key
c->closure(e | expr)OrderedSetexpr применяется повторно, пока не перестанет давать новые элементы

closure проходит по цепочке: self->closure(e | e.eContainer()) — это список контейнеров вплоть до корня.

Навигация по модели

СинтаксисВозвращаетЗначение
o.eContents()Sequence(EObject)объекты, непосредственно содержащиеся в o
o.eContents(T)Sequence(T)то же самое, одного типа или набора типов
o.eAllContents()Sequence(EObject)всё содержимое на любой глубине
o.eAllContents(T)Sequence(T)то же самое, одного типа или набора типов
o.eContainer()EObjectсодержащий объект
o.eContainer(T)Tближайший контейнер заданного типа
o.eContainerOrSelf(T)Tсам o, если он T, иначе его ближайший контейнер этого типа
o.eClass()EClassметакласс o
o.eContainingFeature()EStructuralFeatureхарактеристика контейнера, в которой лежит o
o.eContainmentFeature()EReferenceссылка-композиция, в которой лежит o
o.eGet(name)Objectзначение характеристики, названной строкой
o.eGet(feature)Objectзначение характеристики, заданной объектом
o.eGet(feature, resolve)Objectто же самое; resolve, равное false, оставляет прокси неразрешёнными
o.eCrossReferences()Sequence(EObject)объекты, на которые o ссылается, но не содержит
o.eInverse()OrderedSet(EObject)объекты, ссылающиеся на o
o.eInverse(T)OrderedSet(T)то же самое, одного типа
o.eInverse('feature')OrderedSet(EObject)объекты, ссылающиеся на o через названную характеристику
o.ancestors()Sequence(EObject)все контейнеры o, начиная с ближайшего
o.ancestors(T)Sequence(T)то же самое, одного типа или набора типов
o.siblings()Sequence(EObject)остальные объекты в том же контейнере
o.siblings(T)Sequence(T)то же самое, одного типа или набора типов
o.precedingSiblings()Sequence(EObject)соседи, идущие до o
o.precedingSiblings(T)Sequence(T)то же самое, одного типа или набора типов
o.followingSiblings()Sequence(EObject)соседи, идущие после o
o.followingSiblings(T)Sequence(T)то же самое, одного типа или набора типов

eInverse читает обратные ссылки, которые отслеживаются по всему проекту, и потому находит ссылающиеся объекты и в других моделях. В консоли и в документе он работает, в правиле проверки и в быстром исправлении — возвращает пустое множество. Поэтому проверка, которой нужно узнать, что ссылается на объект, идёт по характеристике — как self.incomingRelationships.

Операции над ресурсами

СинтаксисВозвращаетЗначение
o.eResource()Resourceресурс, содержащий o
o.getURIFragment()Stringфрагмент, идентифицирующий o внутри его ресурса
r.getURI()URIURI ресурса
r.getContents()Sequence(EObject)корни ресурса
r.getContents(T)Sequence(T)корни заданного типа
r.getEObject(fragment)EObjectобъект, который идентифицирует фрагмент
u.lastSegment()Stringпоследний сегмент URI
u.fileExtension()Stringрасширение файла в URI
u.isPlatformResource()Booleanэто platform resource URI
u.isPlatformPlugin()Booleanэто platform plugin URI

Условия и связывание имён

СинтаксисВозвращаетЗначение
if cond then a else b endifтип ветвейусловное выражение; else и endif обязательны
let n = expr in bodyтип bodyсвязать имя на остаток выражения
let n : T = expr in bodyтип bodyто же самое, с явно указанным типом
let n = e1, m = e2 in bodyтип bodyсвязать несколько имён сразу
e | exprлямбда, которую принимают итераторы
e : T | exprто же самое, с явно указанным типом переменной
let named = self.eAllContents(archimate::ArchimateElement)
->select(e | e.name <> null)
in named->size()

Операции, объявленные метамоделью

Операции, объявленные метамоделью на её метаклассах, вызываются как любые другие. В ArchiMate есть, среди прочих:

СинтаксисВозвращаетЗначение
o.getArchimateModel()ArchimateModelмодель, которой принадлежит объект
o.getArchimateConcept()ArchimateConceptконцепт, который представляет объект диаграммы
o.getDiagramModel()DiagramModelдиаграмма, которой принадлежит объект диаграммы

Автодополнение предлагает их наравне со встроенными.

Операции, ничего не возвращающие здесь

Они входят в язык и разбираются без ошибок, но в этом продукте им нечего читать.

СинтаксисПоведение
T.allInstances()сообщает, что провайдер корней не зарегистрирован, и даёт пустую коллекцию; чтобы добраться до всех экземпляров, используйте eAllContents от корня модели
s.promptString(), s.promptInteger(), s.promptLong(), s.promptFloat(), s.promptDouble()читают из терминала, которого у серверного выражения нет
key.getProperty(), key.getProperty(args)читают набор свойств, который пуст