ATL Transformations

Creating Your First ATL Transformation

Learn how to transform models with the Atlas Transformation Language (ATL) using the Families to Persons example.

In this tutorial, you’ll write a transformation that converts a hierarchical family structure into a flat list of persons with full names and gender classification.

You’ll learn how to:

  • Understand source and target metamodels

  • Write ATL helpers for reusable logic

  • Define transformation rules with pattern matching

  • Execute transformations using the swift-atl CLI

30 mins Estimated Time

Section 1

Understand the Metamodels

Before writing the transformation, you need to understand the source and target metamodels.

The Families metamodel organises people into family units with members having specific roles (father, mother, son, daughter).

The Persons metamodel represents individuals as independent entities with full names and gender (Male or Female).

Step 1

Examine the Families metamodel structure.

The metamodel defines two classes: Family (with lastName) and Member (with firstName). Families contain references to father, mother, sons, and daughters.

Families.ecore
1<?xml version="1.0" encoding="UTF-8"?>
2<ecore:EPackage xmi:version="2.0"
3 xmlns:xmi="http://www.omg.org/XMI"
4 xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"
5 name="Families"
6 nsURI="http://www.example.org/families"
7 nsPrefix="families">
8 <eClassifiers xsi:type="ecore:EClass" name="Family">
9 <eStructuralFeatures xsi:type="ecore:EAttribute" name="lastName"/>
10 <eStructuralFeatures xsi:type="ecore:EReference" name="father" eType="#//Member"/>
11 <eStructuralFeatures xsi:type="ecore:EReference" name="mother" eType="#//Member"/>
12 <eStructuralFeatures xsi:type="ecore:EReference" name="sons" upperBound="-1"/>
13 <eStructuralFeatures xsi:type="ecore:EReference" name="daughters" upperBound="-1"/>
14 </eClassifiers>
15 <eClassifiers xsi:type="ecore:EClass" name="Member">
16 <eStructuralFeatures xsi:type="ecore:EAttribute" name="firstName"/>
17 </eClassifiers>
18</ecore:EPackage>

Step 2

Examine the Persons metamodel structure.

The metamodel defines an abstract Person class with a fullName attribute, and two concrete subclasses: Male and Female.

Persons.ecore
1<?xml version="1.0" encoding="UTF-8"?>
2<ecore:EPackage xmi:version="2.0"
3 xmlns:xmi="http://www.omg.org/XMI"
4 xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"
5 name="Persons"
6 nsURI="http://www.example.org/persons"
7 nsPrefix="persons">
8 <eClassifiers xsi:type="ecore:EClass" name="Person" abstract="true">
9 <eStructuralFeatures xsi:type="ecore:EAttribute" name="fullName" lowerBound="1"/>
10 </eClassifiers>
11 <eClassifiers xsi:type="ecore:EClass" name="Male" eSuperTypes="#//Person"/>
12 <eClassifiers xsi:type="ecore:EClass" name="Female" eSuperTypes="#//Person"/>
13</ecore:EPackage>

Section 2

Write Helper Functions

ATL helpers are reusable functions that encapsulate logic. You’ll create two helpers: one to determine if a member is female, and another to get the family surname.

Step 1

Create a new ATL file with the module declaration.

The module specifies the transformation name and declares the source (IN: Families) and target (OUT: Persons) models.

Families2Persons.atl
1-- @path Families=/Families2Persons/Families.ecore
2-- @path Persons=/Families2Persons/Persons.ecore
3
4module Families2Persons;
5create OUT: Persons from IN: Families;

Step 2

Add the isFemale() helper to determine gender.

This context helper checks if a member is a mother or daughter by testing the corresponding family reference.

Families2Persons.atl
1module Families2Persons;
2create OUT: Persons from IN: Families;
3
4helper context Families!Member def: isFemale(): Boolean =
5 if not self.familyMother.oclIsUndefined() then
6 true
7 else
8 if not self.familyDaughter.oclIsUndefined() then
9 true
10 else
11 false
12 endif
13 endif;

Step 3

Add the familyName helper to get the surname.

This helper navigates from a member back to their family to retrieve the surname.

Families2Persons.atl
1helper context Families!Member def: familyName: String =
2 if not self.familyFather.oclIsUndefined() then
3 self.familyFather.lastName
4 else
5 if not self.familyMother.oclIsUndefined() then
6 self.familyMother.lastName
7 else
8 if not self.familySon.oclIsUndefined() then
9 self.familySon.lastName
10 else
11 self.familyDaughter.lastName
12 endif
13 endif
14 endif;

Section 3

Define Transformation Rules

Transformation rules define how source model elements are transformed into target model elements. Rules use pattern matching to select source elements and create corresponding target elements.

Step 1

Add the Member2Male rule for transforming male members.

This rule matches male members (where isFemale() returns false) and creates Male persons.

Families2Persons.atl
1rule Member2Male {
2 from
3 s: Families!Member (not s.isFemale())
4 to
5 t: Persons!Male (
6 fullName <- s.firstName + ' ' + s.familyName
7 )
8}

Step 2

Add the Member2Female rule for transforming female members.

This rule matches female members and creates Female persons.

Families2Persons.atl
1rule Member2Female {
2 from
3 s: Families!Member (s.isFemale())
4 to
5 t: Persons!Female (
6 fullName <- s.firstName + ' ' + s.familyName
7 )
8}

Step 3

Review the complete transformation.

The complete transformation includes the module declaration, two helpers, and two transformation rules.

Families2Persons.atl
1-- @path Families=/Families2Persons/Families.ecore
2-- @path Persons=/Families2Persons/Persons.ecore
3
4module Families2Persons;
5create OUT: Persons from IN: Families;
6
7helper context Families!Member def: isFemale(): Boolean =
8 if not self.familyMother.oclIsUndefined() then
9 true
10 else
11 if not self.familyDaughter.oclIsUndefined() then
12 true
13 else
14 false
15 endif
16 endif;
17
18helper context Families!Member def: familyName: String =
19 if not self.familyFather.oclIsUndefined() then
20 self.familyFather.lastName
21 else
22 if not self.familyMother.oclIsUndefined() then
23 self.familyMother.lastName
24 else
25 if not self.familySon.oclIsUndefined() then
26 self.familySon.lastName
27 else
28 self.familyDaughter.lastName
29 endif
30 endif
31 endif;
32
33rule Member2Male {
34 from
35 s: Families!Member (not s.isFemale())
36 to
37 t: Persons!Male (
38 fullName <- s.firstName + ' ' + s.familyName
39 )
40}
41
42rule Member2Female {
43 from
44 s: Families!Member (s.isFemale())
45 to
46 t: Persons!Female (
47 fullName <- s.firstName + ' ' + s.familyName
48 )
49}

Section 4

Run the Transformation

Execute the transformation to convert the sample Families model into a Persons model.

Step 1

Create a sample Families model.

This sample model contains three families with different members in various roles.

sample-Families.xmi
1<?xml version="1.0" encoding="UTF-8"?>
2<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"
3 xmlns="http://www.example.org/families">
4 <Family lastName="March">
5 <father firstName="Jim"/>
6 <mother firstName="Cindy"/>
7 <sons firstName="Brandon"/>
8 <daughters firstName="Brenda"/>
9 </Family>
10 <Family lastName="Sailor">
11 <father firstName="Peter"/>
12 <mother firstName="Jackie"/>
13 <sons firstName="David"/>
14 <sons firstName="Dylan"/>
15 <daughters firstName="Kelly"/>
16 </Family>
17 <Family lastName="Smith">
18 <father firstName="John"/>
19 <mother firstName="Sarah"/>
20 <daughters firstName="Emma"/>
21 <daughters firstName="Olivia"/>
22 </Family>
23</xmi:XMI>

Step 2

Run the transformation with swift-atl.

Execute the transformation, specifying the source and target files.

Terminal
1swift-atl transform Families2Persons.atl \
2 --source sample-Families.xmi \
3 --target output-Persons.xmi

Step 3

Examine the output Persons model.

Notice how each family member became an individual person with combined first and last names, correctly classified by gender.

output-Persons.xmi
1<?xml version="1.0" encoding="UTF-8"?>
2<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"
3 xmlns="http://www.example.org/persons">
4 <Male fullName="Jim March"/>
5 <Male fullName="Brandon March"/>
6 <Male fullName="Peter Sailor"/>
7 <Male fullName="David Sailor"/>
8 <Male fullName="Dylan Sailor"/>
9 <Male fullName="John Smith"/>
10 <Female fullName="Cindy March"/>
11 <Female fullName="Brenda March"/>
12 <Female fullName="Jackie Sailor"/>
13 <Female fullName="Kelly Sailor"/>
14 <Female fullName="Sarah Smith"/>
15 <Female fullName="Emma Smith"/>
16 <Female fullName="Olivia Smith"/>
17</xmi:XMI>

Check Your Understanding

Question 1 of 3

What is the purpose of the isFemale() helper?

Question 2 of 3

How do transformation rules select which elements to transform?

Question 3 of 3

What happens to the hierarchical family structure during transformation?

ATL Helpers and Guards

Master helper functions and guard conditions to write more sophisticated ATL transformations.