Tutorial | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Downloads


QVT Tutorial - 4

In Eclipse, Click File, New, Other (Ctrl N). Choose "Operational QVT Project", and name it MMA2MMB. The Project Type should be "Create a simple project". Finally, check the "Create artifacts in new QVT Operational Project" box and select "Operational QVT Transformation". Choose a name for the transformation, e.g. MMATransformation.

The transformation "MMATransformation.qvto" now looks like this:

transformation MMATransformation();

main() {

}

The first step of the transformation is to define modeltypes. A modeltype should have a name and a reference (unless the metamodel is defined in the same file as the transformation). Optional attributes are "strict" or "effective" (default), where strict only allows instances which conform exactly to the metamodel. Another option is to add conditions to a modeltype definition, but this is not supported by the current implementation.

A reference can be location specific or a package namespace URI. To use the latter, right-click the QVT Project "MMA2MMB" in the Project Explorer, and choose Properties. Go to "QVT-Settings", "Metamodel Mappings" and Add "platform:/resource/MMB/MMB.ecore" as Target Model URI. You can now refer to it by "http://mmb/1.0".
These are valid modeltype declarations:

-- Declaration with a condition: the instance may differ from the metamodel,
-- but should have exactly one Project object. Location specific reference.
modeltype MMA uses "platform:/resource/MMA/MMA.ecore" where 
{ self.objectsOfType(Project)->size() = 1 };

-- Strict declaration, using a package namespace URI
modeltype MMB "strict" uses "http://mmb/1.0";

The transformation declaration is quite simple: indicate the in- and out metamodels, and give them a name. An existing transformation can be extended or accessed from a new one, it is also possible to have multiple in and out metamodels. Our case is very simple, just use:

transformation MMATransformation(in Source: MMA, out Target: MMB);

Next is the main() function. The purpose of this function is to initialize variables and call the first mapping. In our case, we don't need any initializing:

main() {
 Source.rootObjects()[Project] -> map ProjectToModel();
}

The function rootObjects() returns a Set of elements. We only want Project objects to be in that list (this would be the case anyway since these objects are the only rootObjects), so we add [Project]. This works like a filter and only selects "Project" objects.
The next step is very important. We add the "Set Operator", "->". This operator iterates all elements that are in the Set, and passes them on to the command after "->".
We want to map each Project. Because there can only be one Project object, we could also use a dot "." instead of "->". This dot only applies the command to one Object. Because we don't assign the result of the mapping, we can use either one of them.

The keyword "map" calls a mapping with the name ProjectToModel(). You could also use "xmap" instead of "map". This function returns an exception when the sourceobject cannot be mapped (however, there is a bug in the current implementation: no exception is shown).

The next subject will be the mappings. Continue...