Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
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 Go to next message
John Henbergs is currently offline John HenbergsFriend
Messages: 239
Registered: October 2020
Senior Member
Hi all,

I have the following two metamodels :

Metamodel A
index.php/fa/41237/0/
and Metamodel B
index.php/fa/41238/0/

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 Go to previous messageGo to next message
Christopher Gerking is currently offline Christopher GerkingFriend
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 Go to previous messageGo to next message
John Henbergs is currently offline John HenbergsFriend
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.

index.php/fa/41239/0/

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 Go to previous messageGo to next message
Christopher Gerking is currently offline Christopher GerkingFriend
Messages: 115
Registered: April 2011
Senior Member
John Henbergs wrote on Tue, 02 November 2021 11:50
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.

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:50
Guess 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 #1847639 is a reply to message #1847637] Tue, 02 November 2021 17:11 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 7655
Registered: July 2009
Senior Member
Hi

I find it helpful to sprinkle log statements around a transformation that does not work as I expect.

Regards

Ed Willink
Re: Element is not transformed inside its container [message #1847641 is a reply to message #1847637] Tue, 02 November 2021 19:25 Go to previous messageGo to next message
John Henbergs is currently offline John HenbergsFriend
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.
index.php/fa/41240/0/

When I run the transformation using this model as input, this is the target model:

index.php/fa/41241/0/

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).

index.php/fa/41242/0/

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.
Re: Element is not transformed inside its container [message #1847644 is a reply to message #1847641] Tue, 02 November 2021 21:52 Go to previous messageGo to next message
Christopher Gerking is currently offline Christopher GerkingFriend
Messages: 115
Registered: April 2011
Senior Member
John Henbergs wrote on Tue, 02 November 2021 15:25
But I want to be able to transform it, even if it is the 5th, 10th ... element.

I see. Thus you need some input filtering. OCL's select operation is meant for that. But since you want to obtain a single element, try the any operation with a proper condition as mentioned before:

Quote:

element := self.element->any(e | <some condition to select the element that should be mapped, probably just true>).map Elements();


In your case it should be:
element := self.element -> any(e | e.name = 'A').map toElementA()

This way you could even get rid of the when clause because the source elements are filtered prior to the mapping invocation.

Kind regards
Christopher
Re: Element is not transformed inside its container [message #1847645 is a reply to message #1847644] Tue, 02 November 2021 23:07 Go to previous messageGo to next message
John Henbergs is currently offline John HenbergsFriend
Messages: 239
Registered: October 2020
Senior Member
Thanks, works perfectly well :)
Re: Element is not transformed inside its container [message #1848110 is a reply to message #1847644] Sat, 20 November 2021 18:50 Go to previous messageGo to next message
Jan Crkvic is currently offline Jan CrkvicFriend
Messages: 18
Registered: November 2021
Junior Member
Hello Christopher, could this input filtering be written in the form of a query? If so, would you mind providing an example, on how it would be in the case presented by John?

Cheers!
Re: Element is not transformed inside its container [message #1848126 is a reply to message #1848110] Mon, 22 November 2021 08:45 Go to previous message
Christopher Gerking is currently offline Christopher GerkingFriend
Messages: 115
Registered: April 2011
Senior Member
Hi

Not sure if I got your question right. Of course it can be a query:

query Map :: getElementNamedA() : Element 
{
    return self.element -> any(e | e.name = 'A');
}

mapping Map :: Map2Map() : B::Map 
{
    ...
    element := self.element.getElementNamedA().map toElementA();
    ...
}



Kind regards
Christopher
Previous Topic:Compiling performance
Next Topic:Compiled output
Goto Forum:
  


Current Time: Fri Mar 29 13:29:52 GMT 2024

Powered by FUDForum. Page generated in 0.02287 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top