ATL Transformations

Working with Collections

Learn how to manipulate collections in ATL transformations using OCL collection operations.

In this tutorial, you’ll discover how to iterate, filter, and transform collections of model elements.

You’ll master essential collection operations like collect, select, reject, exists, and forAll.

30 mins Estimated Time

Section 1

Collection Basics

Collections in ATL are manipulated using OCL (Object Constraint Language) operations. These operations provide functional-style collection processing.

Common operations include collect (map), select (filter), and reject (inverse filter).

Step 1

Create a metamodel with collection relationships.

This metamodel defines Department and Course classes with one-to-many relationships.

University.ecore
1<?xml version="1.0" encoding="UTF-8"?>
2<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3 xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="University" nsURI="http://www.example.org/university" nsPrefix="uni">
4 <eClassifiers xsi:type="ecore:EClass" name="Department">
5 <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
6 <eStructuralFeatures xsi:type="ecore:EReference" name="courses" upperBound="-1" eType="#//Course" containment="true"/>
7 </eClassifiers>
8 <eClassifiers xsi:type="ecore:EClass" name="Course">
9 <eStructuralFeatures xsi:type="ecore:EAttribute" name="code" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
10 <eStructuralFeatures xsi:type="ecore:EAttribute" name="title" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
11 <eStructuralFeatures xsi:type="ecore:EAttribute" name="credits" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
12 <eStructuralFeatures xsi:type="ecore:EAttribute" name="level" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
13 </eClassifiers>
14</ecore:EPackage>

Step 2

Use collect to extract values from collections.

The collect operation maps each element to a new value, creating a new collection.

UniversityTransform.atl
1-- @path University=/University/University.ecore
2-- @path Catalog=/Catalog/Catalog.ecore
3
4module UniversityTransform;
5create OUT: Catalog from IN: University;
6
7-- Helper using collect: get all course titles from a department
8helper context University!Department def: courseTitles: Sequence(String) =
9 self.courses->collect(c | c.title);

Step 3

Use select to filter collections.

The select operation creates a new collection containing only elements that satisfy a condition.

UniversityTransform.atl
1-- @path University=/University/University.ecore
2-- @path Catalog=/Catalog/Catalog.ecore
3
4module UniversityTransform;
5create OUT: Catalog from IN: University;
6
7-- Helper using collect: get all course titles from a department
8helper context University!Department def: courseTitles: Sequence(String) =
9 self.courses->collect(c | c.title);
10
11-- Helper using select: get only advanced courses (300+ level)
12helper context University!Department def: advancedCourses: Sequence(University!Course) =
13 self.courses->select(c | c.level >= 300);

Step 4

Use reject for inverse filtering.

The reject operation is the opposite of select, excluding elements that match the condition.

UniversityTransform.atl
1-- @path University=/University/University.ecore
2-- @path Catalog=/Catalog/Catalog.ecore
3
4module UniversityTransform;
5create OUT: Catalog from IN: University;
6
7-- Helper using collect: get all course titles from a department
8helper context University!Department def: courseTitles: Sequence(String) =
9 self.courses->collect(c | c.title);
10
11-- Helper using select: get only advanced courses (300+ level)
12helper context University!Department def: advancedCourses: Sequence(University!Course) =
13 self.courses->select(c | c.level >= 300);
14
15-- Helper using reject: get all courses except introductory (100 level)
16helper context University!Department def: nonIntroductoryCourses: Sequence(University!Course) =
17 self.courses->reject(c | c.level < 200);

Section 2

Advanced Collection Operations

Beyond basic filtering and mapping, OCL provides operations for testing collection properties, computing aggregates, and creating nested collections.

Operations like exists, forAll, size, and isEmpty enable sophisticated collection queries.

Step 1

Use exists to test if any element matches.

The exists operation returns true if at least one element satisfies the condition.

UniversityTransform.atl
1-- @path University=/University/University.ecore
2-- @path Catalog=/Catalog/Catalog.ecore
3
4module UniversityTransform;
5create OUT: Catalog from IN: University;
6
7-- Helper using exists: check if department has any graduate courses
8helper context University!Department def: hasGraduateCourses(): Boolean =
9 self.courses->exists(c | c.level >= 500);

Step 2

Use forAll to test if all elements match.

The forAll operation returns true only if every element satisfies the condition.

UniversityTransform.atl
1-- @path University=/University/University.ecore
2-- @path Catalog=/Catalog/Catalog.ecore
3
4module UniversityTransform;
5create OUT: Catalog from IN: University;
6
7-- Helper using exists: check if department has any graduate courses
8helper context University!Department def: hasGraduateCourses(): Boolean =
9 self.courses->exists(c | c.level >= 500);
10
11-- Helper using forAll: check if all courses have at least 3 credits
12helper context University!Department def: allCoursesSubstantial(): Boolean =
13 self.courses->forAll(c | c.credits >= 3);

Step 3

Combine collection operations.

Chain multiple operations together for complex collection processing.

UniversityTransform.atl
1-- @path University=/University/University.ecore
2-- @path Catalog=/Catalog/Catalog.ecore
3
4module UniversityTransform;
5create OUT: Catalog from IN: University;
6
7-- Helper combining select and collect: get titles of advanced courses
8helper context University!Department def: advancedCourseTitles: Sequence(String) =
9 self.courses
10 ->select(c | c.level >= 300)
11 ->collect(c | c.title);
12
13-- Helper with complex filtering: get high-credit advanced courses
14helper context University!Department def: intensiveAdvancedCourses: Sequence(University!Course) =
15 self.courses
16 ->select(c | c.level >= 300)
17 ->select(c | c.credits >= 4);

Step 4

Build a complete transformation with collection operations.

The complete transformation demonstrates practical collection manipulation in model transformations.

UniversityTransform.atl
1-- @path University=/University/University.ecore
2-- @path Catalog=/Catalog/Catalog.ecore
3
4module UniversityTransform;
5create OUT: Catalog from IN: University;
6
7-- Helper: get titles of advanced courses
8helper context University!Department def: advancedCourseTitles: Sequence(String) =
9 self.courses
10 ->select(c | c.level >= 300)
11 ->collect(c | c.title);
12
13-- Helper: check if department offers graduate program
14helper context University!Department def: hasGraduateProgram(): Boolean =
15 self.courses->exists(c | c.level >= 500);
16
17-- Helper: calculate total credits in department
18helper context University!Department def: totalCredits: Integer =
19 self.courses
20 ->collect(c | c.credits)
21 ->sum();
22
23-- Rule: Transform departments with graduate programs
24rule GraduateDepartment {
25 from
26 s: University!Department (s.hasGraduateProgram())
27 to
28 t: Catalog!Program (
29 name <- s.name,
30 type <- 'Graduate',
31 totalCredits <- s.totalCredits
32 )
33}
34
35-- Rule: Transform undergraduate-only departments
36rule UndergraduateDepartment {
37 from
38 s: University!Department (not s.hasGraduateProgram())
39 to
40 t: Catalog!Program (
41 name <- s.name,
42 type <- 'Undergraduate',
43 totalCredits <- s.totalCredits
44 )
45}

Check Your Understanding

Question 1 of 3

What is the difference between select and reject?

Question 2 of 3

What does collect do to a collection?

Question 3 of 3

Can you chain collection operations together?

Advanced Rule Patterns

Explore advanced ATL rule patterns including lazy rules, called rules, and imperative sections.