Sometimes, a user may need to transform only selected model elements instead of the entire model. There are (at least) three approaches to achieving this:
- mark the elements that need to be transformed
- provide an external (weaving) model that specifies which elements need to be transformed
- ask the user directly during the transformation
Marking elements inside models for various tasks is not a good idea since in this way models can quickly become polluted with unimportant information. The second approach is a lot better but requires the user to construct the weaving model (and possibly a weaving metamodel) before the transformation. The third approach, which is demonstrated shortly, is more interactive and simpler to achieve (no need to construct a weaving metamodel/model).
To demonstrate interactive transformations with ETL we use two simple Tree and Graph metamodels (expressed in Emfatic).
The Tree metamodel
package Tree;
class Tree {
ref Tree#children parent;
val Tree[*]#parent children;
attr String label;
}
The Graph metamodel
package Graph;
class Graph {
val GraphElement[*] elements;
}
abstract class GraphElement {}
class Node extends GraphElement {
ref Edge[*]#source outgoing;
ref Edge[*]#target incoming;
attr String label;
}
class Edge extends GraphElement {
ref Node#incoming target;
ref Node#outgoing source;
}
In this example we need to transform only selected instances of the Tree metaclass in the Tree model into instances of Node and Edge in the Graph model. We achieve this using the ETL transformation that follows. More specifically, to allow the user to explicitly select which instances of Tree need to be transformed, the guard part of the Tree2Node rule uses the UserInput.confirm(question:String, default:String) : Boolean operation to pop-up a confirmation dialog through which the user can select if the specific element will be transformed or not.
ETL source code
rule Tree2Node
transform t : Tree!Tree
to n : Graph!Node {
guard : UserInput.confirm
('Transform tree ' + t.label + '?', true)
n.label := t.label;
var target : Graph!Node := t.parent.equivalent();
if (target.isDefined()) {
var edge := new Graph!Edge;
edge.source := n;
edge.target := target;
}
}