Home » Modeling » QVT-OML » Element is not transformed inside its container
Element is not transformed inside its container [message #1847626] |
Tue, 02 November 2021 14:07 |
John Henbergs Messages: 239 Registered: October 2020 |
Senior Member |
|
|
Hi all,
I have the following two metamodels :
Metamodel A
and Metamodel B
And I am writing the following transformations in QVTo.
modeltype A uses metamodelA('http://www.example.org/metamodelA');
modeltype B uses metamodelB('http://www.example.org/metamodelB');
transformation test(in srcModel:A, out trgModel:B);
main() {
srcModel.rootObjects()[A::Map] -> map Map2Map();
}
mapping Map :: Map2Map() : B::Map
{
element := self.element.map Elements().resolveone(B::Element);
}
mapping Element:: Elements() : B::Element
{
name:=self.name;
}
In he Map2Map() mapping rule, I am using resolveone (otherwise The type 'test::Sequence(Element)' does not conform to the type 'metamodelB::Element' of the property 'element), which makes sense being that in metamodelA we have a 0...* relationship while in metamodelB we have a 0...1 relationship. I am not sure if this is the correct way of doing it, but it works to a certain extent. It gets transformed, but instead of being transformed like this :
Map M1
--- Element E1
It gets transformed like this: (on the same level, when in fact the element should be a child of the map).
Map M1
Element E1
I know that there might be issues (e.g., what will happen if the user creates more than one element in the source model, being that in the target model, the map can contain only one element as its child). But let's pretend the user will only create one.
How can I make sure that the element is placed as a child of the Map and not as its sibling?
Thank you in advance!
|
|
|
Re: Element is not transformed inside its container [message #1847628 is a reply to message #1847626] |
Tue, 02 November 2021 14:19 |
Christopher Gerking Messages: 115 Registered: April 2011 |
Senior Member |
|
|
John Henbergs wrote on Tue, 02 November 2021 10:07
element := self.element.map Elements().resolveone(B::Element);
Resolve operations must be invoked on a source element that was mapped, i.e., one of those elements on which a mapping has been invoked. In your case, resolveone is invoked on the mapping result, which is wrong and will always return null. That's why the link between the Map and the Elememnt is never created.
Try the following:
element := self.element->first().map Elements();
However this requires the 'element' reference to be ordered, otherwise first() is not available. If so, try:
element := self.element->any(e | <some condition to select the element that should be mapped, probably just true>).map Elements();
Are your working with UML profiles in your metamodels? They sometimes refuse to create links between parents and children. If so, please let me know.
Kind regards
Christopher
[Updated on: Tue, 02 November 2021 14:20] Report message to a moderator
|
|
|
Re: Element is not transformed inside its container [message #1847635 is a reply to message #1847628] |
Tue, 02 November 2021 15:50 |
John Henbergs Messages: 239 Registered: October 2020 |
Senior Member |
|
|
Hi Christopher,
First of all, many thanks for your answer. It does work with the example I provided, but wanting to minimise the example as much as possible, I forgot to mention one very important detail.
The target metamodel is actually something like this.
And an element from the source metamodel can be transformed either to an ElementA or ElementB in the target metamodel, depending on the guard.
So I wrote the following transformations :
modeltype A uses metamodelA('http://www.example.org/metamodelA');
modeltype B uses metamodelB('http://www.example.org/metamodelB');
transformation test(in srcModel:A, out trgModel:B);
main() {
srcModel.rootObjects()[A::Map] -> map Map2Map();
}
mapping Map :: Map2Map() : B::Map
{
name:= self.name;
element := self.element -> first().map toElementA();
elementb := self.element.map toElementB();
}
mapping Element:: toElementA() : B::ElementA
when {self.name.matches('A')}
{
name:=self.name;
}
mapping Element:: toElementB() : B::ElementB
when {self.name.matches('B')}
{
name:=self.name;
}
However, this only works if I first create an element that will be transformed into ElementA (before creating any other element). If I don't, then Element-> ElementA will never be transformed. Guess it is because that element is not first on the list, so first() won't really help. Is there another way to achieve this (the transformation should happen no matter when the element is created (no matter its position on the list)).
In ETL I can achieve that using equivalent(), but I am not very familiar with the syntax in QVTo, so I am not sure how to do that.
Thank you in advance!
Best,
John
|
|
|
Re: Element is not transformed inside its container [message #1847637 is a reply to message #1847635] |
Tue, 02 November 2021 16:42 |
Christopher Gerking Messages: 115 Registered: April 2011 |
Senior Member |
|
|
John Henbergs wrote on Tue, 02 November 2021 11:50However, this only works if I first create an element that will be transformed into ElementA (before creating any other element). If I don't, then Element-> ElementA will never be transformed.
I think I don't understand. Obviously, the maping from Element to ElementA can only be executed if there is a matching Element (with name 'A') in the source model. So, of course such an element must be created before executing the transformation - otherwise the mapping will not execute. But that is exactly what the when clause specifies, right?
So I guess the problem is something different. As far as I know, matches(...) accepts some sort of regular expression. If you just want to check whether the name is 'A', write something like when {self.name = 'A'}.
John Henbergs wrote on Tue, 02 November 2021 11:50Guess it is because that element is not first on the list, so first() won't really help.
No, that shouldn't be a problem. If there is some element included, then it should also be the first one.
Did you try to reproduce using the QVTo debugger?
Kind regards
Christopher
[Updated on: Tue, 02 November 2021 16:44] Report message to a moderator
|
|
| |
Re: Element is not transformed inside its container [message #1847641 is a reply to message #1847637] |
Tue, 02 November 2021 19:25 |
John Henbergs Messages: 239 Registered: October 2020 |
Senior Member |
|
|
Hi all,
Ok, let me explain better, as it is not an issue with the guards. This is an example of model A that conforms to metamodel A.
Here I have first created Map map1, then I have created Element B, and then I have created Element A. So the first element in the "element" reference is Element B.
When I run the transformation using this model as input, this is the target model:
As you can see Element A is not transformed, because it is not the first element in the "element" reference (Element B is because that I the one I have created first). Moreover I have included the following line in the transformation, just to check what is going on:
log('message', self.element -> first().map toElementA());
In this case I only get "message".
__________________________________
However, if I first create Element A and then create Element B, they are both transformed, as you can see in the following (because Element A is the first element in the "element" reference list, and therefore is fetched by the first() method).
And the results from the log line is as follows:
message, data: org.eclipse.emf.ecore.impl.DynamicEObjectImpl@1627bcda (eClass: org.eclipse.emf.ecore.impl.EClassImpl@4b8a525 (name: ElementA) (instanceClassName: null) (abstract: false, interface: false))
So being that I am using the first() method, the transformation happens only when Element A is the first element in "element" reference.
But I want to be able to transform it, even if it is the 5th, 10th ... element.
|
|
| | | | |
Goto Forum:
Current Time: Fri Mar 29 13:29:52 GMT 2024
Powered by FUDForum. Page generated in 0.02287 seconds
|