Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Archived » M2M (model-to-model transformation) » [QVTo] How to attach intermediate data that is valid only within the scope of a mapping?
[QVTo] How to attach intermediate data that is valid only within the scope of a mapping? [message #550054] Wed, 28 July 2010 23:02 Go to next message
Ryan is currently offline RyanFriend
Messages: 74
Registered: July 2009
Location: Indiana
Member
The title is the best I could come up with, but I've got a transform that I'm not quite sure how to approach.

Example first model (also not sure of best way to represent model):
Class Color
-attribute red (int)
-attribute green (int)
-attribute blue (int)
Class Item
-attribute itemName (String)
-reference itemColor (type Color)


and the second model is
Class Pair:
-attribute name (String)
-attribute value (String)


And example instance of model 1 would be
Color Red (255,0,0)
Color Green (0, 255, 0)

Item GreenApple (with reference to Green)
Item RedApple (with reference to Red)
Item Cherry (with reference to Red)


and the transform would be
name            value
color[0].red    255
color[0].green  0
color[0].blue   0
color[1].red    0
color[1].green  255
color[1].blue   0
item[0].name    RedApple
item[0].color   0
item[1].name    GreenApple
item[1].color   1
item[2].name    Cherry
item[2].color   0


So as I iterate over the items, I'll map the color (which i assume I'll need a variable to hold the index I'm at), but I don't want to map red twice, so I want to be able the next time I see red, to just get the index, and not map it to color[2]. I know the string string model is not very good, but that's what I've got to generate. I don't know enough about QVTO and it may be something I just end up coding in Java.

Thanks,
Ryan

[Updated on: Fri, 30 July 2010 20:14]

Report message to a moderator

Re: [QVTo] How to avoid mapping the same object twice? [message #550076 is a reply to message #550054] Thu, 29 July 2010 05:07 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 7129
Registered: July 2009
Senior Member
Hi Ryan

> I don't know enough
> about QVTO and it may be something I just end up coding in Java.

This is a fundamental requirement for a model language. See

8.1.10 Updating objects and resolving object references

in the QVT specification.

Regards

Ed Willink
Re: [QVTo] How to avoid mapping the same object twice? [message #550209 is a reply to message #550054] Thu, 29 July 2010 14:23 Go to previous messageGo to next message
Ryan is currently offline RyanFriend
Messages: 74
Registered: July 2009
Location: Indiana
Member
Thanks Ed,
I read through that and have also read through 13.5.6 of the DSL book, and must admit, I still am not sure how to apply those tools to this scenario. I realized after I posted that it is a bit more complex as there are times when I do want to remap and times I don't. The original model has a list of items that will map to a collection of pairs called itemdata, and the colors for each set of items needs to be mapped into that itemdata.

Revised example below.
Class Color
-attribute red (int)
-attribute green (int)
-attribute blue (int)
Class ColorList
-reference colors (Color) 0..*
Class Item
-attribute itemName (String)
-reference itemColor (type Color)
Class ItemList
-reference items (Item) 0..*


Class Pair:
-attribute name (String)
-attribute value (String)
Class ItemData
-reference data (Pair) 0..*


ColorList myColorList
-Color Red (255,0,0)
-Color Green (0, 255, 0)

ItemList list1
-Item RedApple (with reference to Red)
-Item GreenApple (with reference to Green)
-Item Cherry (with reference to Red)

ItemList list2
-Item Pear (with reference to Green)
-Item Strawberry (with reference to Red)



ItemData datalist1
name            value
color[0].red    255
color[0].green  0
color[0].blue   0
color[1].red    0
color[1].green  255
color[1].blue   0
item[0].name    RedApple
item[0].color   0
item[1].name    GreenApple
item[1].color   1
item[2].name    Cherry
item[2].color   0

ItemData datalist2
name            value
color[0].red    0
color[0].green  255
color[0].blue   0
color[1].red    255
color[1].green  0
color[1].blue   0
item[0].name    Pear
item[0].color   0
item[1].name    Strawberry
item[1].color   1


I planned on having a mapping
mapping Model1::ItemList::itemList2itemData() : Model2::ItemData

and I assume that I'll somehow use the resolve within that mapping to get previously mapped colors within that mapping. But after I map list 1 (which would skip the second mapping of red), mapping list2 needs to also map the colors again into the second itemdata.

Also, the resolve would get me a reference to the object Pairs, but to get the index that I really need, I'd need to parse that string, or add an attribute index to Pairs to hold the index.

Thanks,
Ryan
Re: [QVTo] How to avoid mapping the same object twice? [message #550259 is a reply to message #550209] Thu, 29 July 2010 16:13 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 7129
Registered: July 2009
Senior Member
Hi Ryan

I'm really only beginning to learn QVTo myself. I've been surprised how
well it does simple mappings and how badly it does even slightly complex
pattern conversions. QVTr wouldn't have been much better. I found that
it was only once I drew UMLX diagrams that I could see what I was trying
to do and then decompose it into what QVTo could do. I found the
explicit UMLX traceability conversion operator invaluable, but since I
defined it, perhaps that's not surprising;
http://www.eclipse.org/gmt/umlx/doc/index.html

Until you know what you want to do you can't expect the tool to do it
for you.

If what you want to do is too complex, you may find it easier to use
multiple passes, or a side analysis.

Regards

Ed Willink

On 29/07/2010 15:23, Ryan wrote:
> Thanks Ed,
> I read through that and have also read through 13.5.6 of the DSL book,
> and must admit, I still am not sure how to apply those tools to this
> scenario. I realized after I posted that it is a bit more complex as
> there are times when I do want to remap and times I don't. The original
> model has a list of items that will map to a collection of pairs called
> itemdata, and the colors for each set of items needs to be mapped into
> that itemdata.
>
> Revised example below.
> Class Color
> -attribute red (int)
> -attribute green (int)
> -attribute blue (int)
> Class ColorList
> -reference colors (Color) 0..*
> Class Item
> -attribute itemName (String)
> -reference itemColor (type Color)
> Class ItemList
> -reference items (Item) 0..*
>
>
> Class Pair:
> -attribute name (String)
> -attribute value (String)
> Class ItemData
> -reference data (Pair) 0..*
>
>
> ColorList myColorList
> -Color Red (255,0,0)
> -Color Green (0, 255, 0)
>
> ItemList list1
> -Item RedApple (with reference to Red)
> -Item GreenApple (with reference to Green)
> -Item Cherry (with reference to Red)
>
> ItemList list2
> -Item Pear (with reference to Green)
> -Item Strawberry (with reference to Red)
>
>
>
> ItemData datalist1
> name value
> color[0].red 255
> color[0].green 0
> color[0].blue 0
> color[1].red 0
> color[1].green 255
> color[1].blue 0
> item[0].name RedApple
> item[0].color 0
> item[1].name GreenApple
> item[1].color 1
> item[2].name Cherry
> item[2].color 0
>
> ItemData datalist2
> name value
> color[0].red 0
> color[0].green 255
> color[0].blue 0
> color[1].red 255
> color[1].green 0
> color[1].blue 0
> item[0].name Pear
> item[0].color 0
> item[1].name Strawberry
> item[1].color 1
>
> I planned on having a mapping
> mapping Model1::ItemList::itemList2itemData() : Model2::ItemData
> and I assume that I'll somehow use the resolve within that mapping to
> get previously mapped colors within that mapping. But after I map list 1
> (which would skip the second mapping of red), mapping list2 needs to
> also map the colors again into the second itemdata.
> Also, the resolve would get me a reference to the object Pairs, but to
> get the index that I really need, I'd need to parse that string, or add
> an attribute index to Pairs to hold the index.
>
> Thanks,
> Ryan
Re: [QVTo] How to avoid mapping the same object twice? [message #550272 is a reply to message #550259] Thu, 29 July 2010 17:15 Go to previous messageGo to next message
Ryan is currently offline RyanFriend
Messages: 74
Registered: July 2009
Location: Indiana
Member
Here is a quick bit of java pseudo code for doing this in Java.

public int mappingColor(ItemData data, Color color) {
	if (/*color has not been mapped in data*/){
		int nextInt = /* get total number of colors mapped in this ItemData */
		data.addPair("color[" + nextInt + "].red", color.getRed().toString());
		// add green
		// add blue
		// save nextInt for this color/data combo
	}
	return intForColor;
}


public ItemData mappingItemList(ItemList list) {
	ItemData retVal = new ItemData();
	int index = 0;

	for (Item i : list) {
		retVal.addPair("item[" + index + "].name", i.getName());
		retVal.addPair("item[" + index + "].color", mappingColor(retVal, i.getColor());
		index++;
	}
	return retVal;
} 


Basically, I'd call the mapping for the color and if it has not been mapped for a particular ItemData, add that color to the itemdata and save the int in some data structure that will be used to look up next time that the mappingColor is called with the same itemdata and color object, so that the int will just be returned.

I took a look at the doc "UMLX - A Graphical Transformation Language for MDA" from your page. Do you have an eclipse plugin for creating these transform diagrams? I could sketch one out on pencil/paper, but that doesn't help for conveying via a forum.
Re: [QVTo] How to avoid mapping the same object twice? [message #550281 is a reply to message #550272] Thu, 29 July 2010 18:01 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 7129
Registered: July 2009
Senior Member
Hi Ryan

> Basically, I'd call the mapping for the color and if it has not been
> mapped for a particular ItemData, add that color to the itemdata and
> save the int in some data structure that will be used to look up next
> time that the mappingColor is called with the same itemdata and color
> object, so that the int will just be returned.

Which is why transformation tools are so much more powerful than Java.
In QVTo you can do this with intermediate data.
In QVTc you do this is the middle model.
In QVTr it's automatic.

> I took a look at the doc "UMLX - A Graphical Transformation Language for
> MDA" from your page. Do you have an eclipse plugin for creating these
> transform diagrams? I could sketch one out on pencil/paper, but that
> doesn't help for conveying via a forum.

Not really. UMLX has been through many half finished dev phases. I'm
really looking forward to getting back to UMLX one day.

Regards

Ed Willink
Re: [QVTo] How to avoid mapping the same object twice? [message #550303 is a reply to message #550054] Thu, 29 July 2010 20:39 Go to previous messageGo to next message
Sergey Boyko is currently offline Sergey BoykoFriend
Messages: 171
Registered: July 2009
Senior Member
Hi Ryan,

Single mapping invocation is the fundamental QVTo behavior (see 8.2.1.15
MappingOperation, section Execution Semantics).

In short:
- all the 'in' and 'inout' parameters of the mapping are ordered as a tuple
- mapping guard (when clause) is checked. if failed then 'null' is returned
- trace records for the mapping are checked to match parameters tuple.
if matched then all 'out' parameters of the mapping are filled from the
found trace record and mapping exists
- mapping is executed and new trace record is created (mapping in/inout
parameters tuple to out parameters)


For example consider the following:

transformation transf();
intermediate class MyInClass { name : String; }
intermediate class MyOutClass { value : Integer; }

main() {
var s := Sequence{
object MyInClass{name := '11'},
object MyInClass{name := '21'},
object MyInClass{name := '11'}
};

var s1 := s->collect(i|i.name.map name2value());
assert fatal (s1->size() = 3);
assert fatal (s1->at(1) = s1->at(3));
}

mapping String::name2value() : MyOutClass {
value := self.toInteger();
}


Also look at thread
http://www.eclipse.org/forums/index.php?t=msg&goto=91769 &
There singleton pattern is described using single mapping invocation
behavior.


Regards,
Sergey


Ryan wrote:
> The title is the best I could come up with, but I've got a transform
> that I'm not quite sure how to approach.
>
> Example first model (also not sure of best way to represent model):
> Class Color
> -attribute red (int)
> -attribute green (int)
> -attribute blue (int)
> Class Item
> -attribute itemName (String)
> -reference itemColor (type Color)
>
> and the second model is Class Pair:
> -attribute name (String)
> -attribute value (String)
>
> And example instance of model 1 would be Color Red (255,0,0)
> Color Green (0, 255, 0)
>
> Item GreenApple (with reference to Green)
> Item RedApple (with reference to Red)
> Item Cherry (with reference to Red)
>
> and the transform would be
>
> name value
> color[0].red 255
> color[0].green 0
> color[0].blue 0
> color[1].red 0
> color[1].green 255
> color[1].blue 0
> item[0].name RedApple
> item[0].color 0
> item[1].name GreenApple
> item[1].color 1
> item[2].name Cherry
> item[2].color 0
>
>
> So as I iterate over the items, I'll map the color (which i assume I'll
> need a variable to hold the index I'm at), but I don't want to map red
> twice, so I want to be able the next time I see red, to just get the
> index, and not map it to color[2]. I know the string string model is
> not very good, but that's what I've got to generate. I don't know
> enough about QVTO and it may be something I just end up coding in Java.
>
> Thanks,
> Ryan
Re: [QVTo] How to avoid mapping the same object twice? [message #550305 is a reply to message #550303] Thu, 29 July 2010 20:45 Go to previous messageGo to next message
Sergey Boyko is currently offline Sergey BoykoFriend
Messages: 171
Registered: July 2009
Senior Member
So the answer on the title question (How to avoid mapping the same
object twice?) - it's done automatically according to the mapping
specification.


Sergey Boyko wrote:
> Hi Ryan,
>
> Single mapping invocation is the fundamental QVTo behavior (see 8.2.1.15
> MappingOperation, section Execution Semantics).
>
> In short:
> - all the 'in' and 'inout' parameters of the mapping are ordered as a tuple
> - mapping guard (when clause) is checked. if failed then 'null' is returned
> - trace records for the mapping are checked to match parameters tuple.
> if matched then all 'out' parameters of the mapping are filled from the
> found trace record and mapping exists
> - mapping is executed and new trace record is created (mapping in/inout
> parameters tuple to out parameters)
>
>
> For example consider the following:
>
> transformation transf();
> intermediate class MyInClass { name : String; }
> intermediate class MyOutClass { value : Integer; }
>
> main() {
> var s := Sequence{
> object MyInClass{name := '11'},
> object MyInClass{name := '21'},
> object MyInClass{name := '11'}
> };
>
> var s1 := s->collect(i|i.name.map name2value());
> assert fatal (s1->size() = 3);
> assert fatal (s1->at(1) = s1->at(3));
> }
>
> mapping String::name2value() : MyOutClass {
> value := self.toInteger();
> }
>
>
> Also look at thread
> http://www.eclipse.org/forums/index.php?t=msg&goto=91769 &
> There singleton pattern is described using single mapping invocation
> behavior.
>
>
> Regards,
> Sergey
>
>
> Ryan wrote:
>> The title is the best I could come up with, but I've got a transform
>> that I'm not quite sure how to approach.
>>
>> Example first model (also not sure of best way to represent model):
>> Class Color
>> -attribute red (int)
>> -attribute green (int)
>> -attribute blue (int)
>> Class Item
>> -attribute itemName (String)
>> -reference itemColor (type Color)
>>
>> and the second model is Class Pair:
>> -attribute name (String)
>> -attribute value (String)
>>
>> And example instance of model 1 would be Color Red (255,0,0)
>> Color Green (0, 255, 0)
>>
>> Item GreenApple (with reference to Green)
>> Item RedApple (with reference to Red)
>> Item Cherry (with reference to Red)
>>
>> and the transform would be
>>
>> name value
>> color[0].red 255
>> color[0].green 0
>> color[0].blue 0
>> color[1].red 0
>> color[1].green 255
>> color[1].blue 0
>> item[0].name RedApple
>> item[0].color 0
>> item[1].name GreenApple
>> item[1].color 1
>> item[2].name Cherry
>> item[2].color 0
>>
>>
>> So as I iterate over the items, I'll map the color (which i assume
>> I'll need a variable to hold the index I'm at), but I don't want to
>> map red twice, so I want to be able the next time I see red, to just
>> get the index, and not map it to color[2]. I know the string string
>> model is not very good, but that's what I've got to generate. I don't
>> know enough about QVTO and it may be something I just end up coding in
>> Java.
>>
>> Thanks,
>> Ryan
Re: [QVTo] How to avoid mapping the same object twice? [message #550318 is a reply to message #550303] Thu, 29 July 2010 21:28 Go to previous messageGo to next message
Ryan is currently offline RyanFriend
Messages: 74
Registered: July 2009
Location: Indiana
Member
Thanks Sergey for the insight into how mappings really work.

Ok, I think I may have figured out a way to accomplish what I want, but I'll run it by you guys first.

So it seems like what I need to do is attach intermediate data with the int value to the colors object (from model 1) when i do the mapping for the color. In the mapping for the itemList2itemData(), first check that intermediate data for the int, and use it if it is set. Otherwise go ahead with the mapping and save the int in the intermediate data. Then clean out the intermediate data for all the colors just before leaving the itemList2itemData().

Sergey, thanks also for the eclipsecon 09 pdf on qvto, that helped clear up a few things that the DSL book didn't quite explain clearly.

Edit:
After thinking it through, I'm not sure that would work. I would somehow need to set that those mappings for colors are valid only in the scope of the mapping of the itemList2itemData(), not the entire transform. Is there a way to rescope a mapping from the transform level down to a mapping within the transform level?

Edit 2:
Perhaps as a way to sort out the mapping, for the mapping Model1::Color::color2pairs() : Sequence(Model1::Pair) have it take as an in parameter the itemData object that is created in the itemList2itemData() mapping.

[Updated on: Thu, 29 July 2010 21:46]

Report message to a moderator

Re: [QVTo] How to avoid mapping the same object twice? [message #550319 is a reply to message #550305] Thu, 29 July 2010 21:42 Go to previous messageGo to next message
Ryan is currently offline RyanFriend
Messages: 74
Registered: July 2009
Location: Indiana
Member
Sergey Boyko wrote on Thu, 29 July 2010 16:45
So the answer on the title question (How to avoid mapping the same
object twice?) - it's done automatically according to the mapping
specification.


Yeah, I guess the title question isn't accurate, I should probably change it, but not quite sure how to convey my question in a few words.
Re: [QVTo] How to avoid mapping the same object twice? [message #550407 is a reply to message #550054] Fri, 30 July 2010 09:36 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: koen.yskout.cs.kuleuven.be

Ryan,

I think something along the following works (for your extended models
given somewhere else in this thread). By using a mapping to generate the
index of the color for a certain ItemList, you can re-use the result of
that mapping. (The index is an integer and needs to be wrapped in an
object, otherwise it cannot be used as the result from a mapping).
You can look at the code below for details (I tested it on your
examples, and it does what I understand you want to achieve :p)

Kind regards,
Koen



modeltype MODEL1 "strict" uses "http://firstmodel";
modeltype MODEL2 "strict" uses "http://secondmodel";

transformation First2Second(in model1 : MODEL1, out model2 : MODEL2);

// Wrapper object for an integer
intermediate class Index {
indexValue : Integer;
}
intermediate property ItemList::nextColorIndex : Integer;
intermediate property ItemList::nextItemIndex : Integer;

main() {
model1.rootObjects()[FirstModel]->map first2Second();
}

mapping FirstModel::first2Second() : SecondModel {
itemData := self.itemList.map itemList2ItemData(self.colorList);
}

mapping ItemList::itemList2ItemData(colorList : ColorList) : ItemData {
init {
self.nextColorIndex := 0;
self.nextItemIndex := 0;
}
name := self.name + 'data';
data := colorList.colors->color2Pairs(self)->flatten();
data += self.items->item2Pairs(self)->flatten();
}

// Map a color to an index in the context of a given ItemList.
// Always returns same Index object when called using the same (Color,
ItemList) pair.
mapping Color::color2Index(list : ItemList) : Index {
indexValue := list.nextColorIndex;
list.nextColorIndex := list.nextColorIndex + 1;
}

mapping Item::item2Index(list : ItemList) : Index {
indexValue := list.nextItemIndex;
list.nextItemIndex := list.nextItemIndex + 1;
}

helper Color::color2PairAttributeName(list: ItemList, attribute :
String) : String {
var index := self.map color2Index(list).indexValue;
return indexedNameAttribute('color', index, attribute);
}

helper Item::item2PairAttributeName(list: ItemList, attribute : String)
: String {
var index := self.map item2Index(list).indexValue;
return indexedNameAttribute('item', index, attribute);
}

helper indexedNameAttribute(name : String, index : Integer, attribute :
String) : String {
return name + '[' + index.toString() + '].' + attribute;
}

helper Color::color2Pairs(list : ItemList) : Sequence(Pair) {
return Sequence {
object Pair {
name := self.color2PairAttributeName(list, 'red');
value := self.red.toString();
},
object Pair {
name := self.color2PairAttributeName(list, 'green');
value := self.green.toString();
},
object Pair {
name := self.color2PairAttributeName(list, 'blue');
value := self.blue.toString();
}
}
}

helper Item::item2Pairs(list : ItemList) : Sequence(Pair) {
return Sequence {
object Pair {
name := self.item2PairAttributeName(list, 'name');
value := self.itemName;
},
object Pair {
name := self.item2PairAttributeName(list, 'color');
value := self.itemColor.map color2Index(list).indexValue.toString();
}
}
}
Re: [QVTo] How to avoid mapping the same object twice? [message #550533 is a reply to message #550407] Fri, 30 July 2010 17:04 Go to previous messageGo to next message
Ryan is currently offline RyanFriend
Messages: 74
Registered: July 2009
Location: Indiana
Member
Thanks Koen for the sample code. I understand better now how to get qvto to do what I want it to do. I got it to pretty much work how I want (I only have one color list, and only colors for a given item list should end up in an item data set), but can't seem to figure out why all the pairs end up at the root of model 2 instead of within each ItemData. The mapping itemList2itemData() stores the pairs returned from item2pairs() in it's data field, but when this gets run, they end up as children of the root of the model. Any thoughs? I have a feeling I'm overlooking something simple here.

Here is the modified code:

modeltype Model1 "strict" uses "http://org.example/models/1.0/model1";
modeltype Model2 "strict" uses "http://org.example/models/1.0/model2";

transformation First2Second(in model1 : Model1, out model2 : Model2);

// Wrapper object for an integer
intermediate class Index {
	indexValue : Integer;
}
intermediate property ItemList::nextColorIndex : Integer;
intermediate property ItemList::nextItemIndex : Integer;

main() {
	model1.objectsOfType(Model1Root)->map first2Second();
}

mapping Model1::Model1Root::first2Second() : Model2::Model2Root {
	dataLists := self.products.map itemList2ItemData()->asOrderedSet();
}

mapping ItemList::itemList2ItemData() : ItemData {
	init {
		self.nextColorIndex := 0;
		self.nextItemIndex := 0;
	}
	name := self.name + 'data';
	data := self.items.map item2Pairs(self)->asOrderedSet();
}

// Map a color to an index in the context of a given ItemList.
// Always returns same Index object when called using the same (Color,ItemList) pair.
mapping Color::color2Index(list : ItemList) : Index {
	indexValue := list.nextColorIndex;
	list.nextColorIndex := list.nextColorIndex + 1;
}

mapping Item::item2Index(list : ItemList) : Index {
	indexValue := list.nextItemIndex;
	list.nextItemIndex := list.nextItemIndex + 1;
}

helper Color::color2PairAttributeName(list: ItemList, attribute : String) : String {
	var index := self.map color2Index(list).indexValue;
	return indexedNameAttribute('color', index, attribute);
}

helper Item::item2PairAttributeName(list: ItemList, attribute : String)	: String {
	var index := self.map item2Index(list).indexValue;
	return indexedNameAttribute('item', index, attribute);
}

helper indexedNameAttribute(name : String, index : Integer, attribute :	String) : String {
	return name + '[' + index.toString() + '].' + attribute;
}

mapping Color::color2Pairs(list : ItemList) : Sequence(Pair) {
	result := Sequence {
		object Pair {
			name := self.color2PairAttributeName(list, 'red');
			value := self.red.toString();
		},
		object Pair {
			name := self.color2PairAttributeName(list, 'green');
			value := self.green.toString();
		},
		object Pair {
			name := self.color2PairAttributeName(list, 'blue');
			value := self.blue.toString();
		}
	}
}

mapping Item::item2Pairs(list : ItemList) : Sequence(Pair) {
	result := Sequence {
		object Pair {
			name := self.item2PairAttributeName(list, 'name');
			value := self.itemName;
		},
		object Pair {
			name := self.item2PairAttributeName(list, 'color');
			value := self.itemColor.map color2Index(list).indexValue.toString();
		}
	};
	result += self.itemColor.map color2Pairs(list)->asOrderedSet();
}


And I couldn't figure out how to attach files to this post, so here are my Model1.ecore
<?xml version="1.0" encoding="UTF-8"?>
<ecore:EPackage xmi:version="2.0"
    xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="model1"
    nsURI="http://org.example/models/1.0/model1" nsPrefix="org.example.models">
  <eClassifiers xsi:type="ecore:EClass" name="Color">
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="red" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="green" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="blue" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="Item">
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="itemName" lowerBound="1"
        eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
    <eStructuralFeatures xsi:type="ecore:EReference" name="itemColor" lowerBound="1"
        eType="#//Color"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="ColorList">
    <eStructuralFeatures xsi:type="ecore:EReference" name="colors" upperBound="-1"
        eType="#//Color" containment="true"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="ItemList">
    <eStructuralFeatures xsi:type="ecore:EReference" name="items" upperBound="-1"
        eType="#//Item" containment="true"/>
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="Model1Root">
    <eStructuralFeatures xsi:type="ecore:EReference" name="products" upperBound="-1"
        eType="#//ItemList" containment="true"/>
    <eStructuralFeatures xsi:type="ecore:EReference" name="colorData" lowerBound="1"
        eType="#//ColorList" containment="true"/>
  </eClassifiers>
</ecore:EPackage>


And my Model2.ecore:
<?xml version="1.0" encoding="UTF-8"?>
<ecore:EPackage xmi:version="2.0"
    xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="model2"
    nsURI="http://org.example/models/1.0/model2" nsPrefix="org.example.models">
  <eClassifiers xsi:type="ecore:EClass" name="Model2Root">
    <eStructuralFeatures xsi:type="ecore:EReference" name="dataLists" upperBound="-1"
        eType="#//ItemData" containment="true"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="ItemData">
    <eStructuralFeatures xsi:type="ecore:EReference" name="data" upperBound="-1" eType="#//Pair"
        containment="true"/>
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="Pair">
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" lowerBound="1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
  </eClassifiers>
</ecore:EPackage>

[Updated on: Fri, 30 July 2010 17:05]

Report message to a moderator

Re: [QVTo] How to avoid mapping the same object twice? [message #550550 is a reply to message #550533] Fri, 30 July 2010 18:38 Go to previous messageGo to next message
Ed Willink is currently offline Ed WillinkFriend
Messages: 7129
Registered: July 2009
Senior Member
Hi Ryan

All the created elements that have no container are contained by the root.

Mapping compositions is easy. Mapping aggregations is much harder.
You'll probably need something like this:

mapping Base::TemplateBindingCS::decorateTemplateBinding(inout dict :
Dict(String,Pivot::Element)) : Pivot::TemplateBinding {
init {
result := self.resolveone(Pivot::TemplateBinding);
if result->isEmpty() then { -- should never happen
result := invalid;
}
else if result.parameterSubstitution->isEmpty() then {
result.parameterSubstitution := self.ownedParameterSubstitution->map
decorateTemplateParameterSubstitution(dict);
}
endif endif;
}
}

To cope with the three cases and workaround the lack of return support.

Target does not exist and needs creating.
Target exists but is not configured.
Target already exists and needs configuring.

You are currently creating new targets for the last two cases.

Regards

Ed Willink


On 30/07/2010 18:04, Ryan wrote:
> Thanks Koen for the sample code. I understand better now how to get
> qvto to do what I want it to do. I got it to pretty much work how I
> want, but can't seem to figure out why all the pairs end up at the root
> of model 2 instead of within each ItemData. The mapping
> itemList2itemData() stores the pairs returned from item2pairs() in it's
> data field, but when this gets run, they end up as children of the root
> of the model. Any thoughs? I have a feeling I'm overlooking something
> simple here.
>
> Here is the modified code:
>
> modeltype Model1 "strict" uses "http://org.example/models/1.0/model1";
> modeltype Model2 "strict" uses "http://org.example/models/1.0/model2";
>
> transformation First2Second(in model1 : Model1, out model2 : Model2);
>
> // Wrapper object for an integer
> intermediate class Index {
> indexValue : Integer;
> }
> intermediate property ItemList::nextColorIndex : Integer;
> intermediate property ItemList::nextItemIndex : Integer;
>
> main() {
> model1.objectsOfType(Model1Root)->map first2Second();
> }
>
> mapping Model1::Model1Root::first2Second() : Model2::Model2Root {
> dataLists := self.products.map itemList2ItemData()->asOrderedSet();
> }
>
> mapping ItemList::itemList2ItemData() : ItemData {
> init {
> self.nextColorIndex := 0;
> self.nextItemIndex := 0;
> }
> name := self.name + 'data';
> data := self.items.map item2Pairs(self)->asOrderedSet();
> }
>
> // Map a color to an index in the context of a given ItemList.
> // Always returns same Index object when called using the same
> (Color,ItemList) pair.
> mapping Color::color2Index(list : ItemList) : Index {
> indexValue := list.nextColorIndex;
> list.nextColorIndex := list.nextColorIndex + 1;
> }
>
> mapping Item::item2Index(list : ItemList) : Index {
> indexValue := list.nextItemIndex;
> list.nextItemIndex := list.nextItemIndex + 1;
> }
>
> helper Color::color2PairAttributeName(list: ItemList, attribute :
> String) : String {
> var index := self.map color2Index(list).indexValue;
> return indexedNameAttribute('color', index, attribute);
> }
>
> helper Item::item2PairAttributeName(list: ItemList, attribute : String)
> : String {
> var index := self.map item2Index(list).indexValue;
> return indexedNameAttribute('item', index, attribute);
> }
>
> helper indexedNameAttribute(name : String, index : Integer, attribute :
> String) : String {
> return name + '[' + index.toString() + '].' + attribute;
> }
>
> mapping Color::color2Pairs(list : ItemList) : Sequence(Pair) {
> result := Sequence {
> object Pair {
> name := self.color2PairAttributeName(list, 'red');
> value := self.red.toString();
> },
> object Pair {
> name := self.color2PairAttributeName(list, 'green');
> value := self.green.toString();
> },
> object Pair {
> name := self.color2PairAttributeName(list, 'blue');
> value := self.blue.toString();
> }
> }
> }
>
> mapping Item::item2Pairs(list : ItemList) : Sequence(Pair) {
> result := Sequence {
> object Pair {
> name := self.item2PairAttributeName(list, 'name');
> value := self.itemName;
> },
> object Pair {
> name := self.item2PairAttributeName(list, 'color');
> value := self.itemColor.map color2Index(list).indexValue.toString();
> }
> };
> result += self.itemColor.map color2Pairs(list)->asOrderedSet();
> }
>
> And I couldn't figure out how to attach files to this post, so here are
> my Model1.ecore
> <?xml version="1.0" encoding="UTF-8"?>
> <ecore:EPackage xmi:version="2.0"
> xmlns:xmi="http://www.omg.org/XMI"
> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
> xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="model1"
> nsURI="http://org.example/models/1.0/model1" nsPrefix="org.example.models">
> <eClassifiers xsi:type="ecore:EClass" name="Color">
> <eStructuralFeatures xsi:type="ecore:EAttribute" name="red"
> lowerBound="1" eType="ecore:EDataType
> http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
> <eStructuralFeatures xsi:type="ecore:EAttribute" name="green"
> lowerBound="1" eType="ecore:EDataType
> http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
> <eStructuralFeatures xsi:type="ecore:EAttribute" name="blue"
> lowerBound="1" eType="ecore:EDataType
> http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
> <eStructuralFeatures xsi:type="ecore:EAttribute" name="name"
> lowerBound="1" eType="ecore:EDataType
> http://www.eclipse.org/emf/2002/Ecore#//EString"/>
> </eClassifiers>
> <eClassifiers xsi:type="ecore:EClass" name="Item">
> <eStructuralFeatures xsi:type="ecore:EAttribute" name="itemName"
> lowerBound="1"
> eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
> <eStructuralFeatures xsi:type="ecore:EReference" name="itemColor"
> lowerBound="1"
> eType="#//Color"/>
> </eClassifiers>
> <eClassifiers xsi:type="ecore:EClass" name="ColorList">
> <eStructuralFeatures xsi:type="ecore:EReference" name="colors"
> upperBound="-1"
> eType="#//Color" containment="true"/>
> </eClassifiers>
> <eClassifiers xsi:type="ecore:EClass" name="ItemList">
> <eStructuralFeatures xsi:type="ecore:EReference" name="items"
> upperBound="-1"
> eType="#//Item" containment="true"/>
> <eStructuralFeatures xsi:type="ecore:EAttribute" name="name"
> lowerBound="1" eType="ecore:EDataType
> http://www.eclipse.org/emf/2002/Ecore#//EString"/>
> </eClassifiers>
> <eClassifiers xsi:type="ecore:EClass" name="Model1Root">
> <eStructuralFeatures xsi:type="ecore:EReference" name="products"
> upperBound="-1"
> eType="#//ItemList" containment="true"/>
> <eStructuralFeatures xsi:type="ecore:EReference" name="colorData"
> lowerBound="1"
> eType="#//ColorList" containment="true"/>
> </eClassifiers>
> </ecore:EPackage>
>
>
> And my Model2.ecore:
> <?xml version="1.0" encoding="UTF-8"?>
> <ecore:EPackage xmi:version="2.0"
> xmlns:xmi="http://www.omg.org/XMI"
> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
> xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="model2"
> nsURI="http://org.example/models/1.0/model2" nsPrefix="org.example.models">
> <eClassifiers xsi:type="ecore:EClass" name="Model2Root">
> <eStructuralFeatures xsi:type="ecore:EReference" name="dataLists"
> upperBound="-1"
> eType="#//ItemData" containment="true"/>
> </eClassifiers>
> <eClassifiers xsi:type="ecore:EClass" name="ItemData">
> <eStructuralFeatures xsi:type="ecore:EReference" name="data"
> upperBound="-1" eType="#//Pair"
> containment="true"/>
> <eStructuralFeatures xsi:type="ecore:EAttribute" name="name"
> lowerBound="1" eType="ecore:EDataType
> http://www.eclipse.org/emf/2002/Ecore#//EString"/>
> </eClassifiers>
> <eClassifiers xsi:type="ecore:EClass" name="Pair">
> <eStructuralFeatures xsi:type="ecore:EAttribute" name="name"
> lowerBound="1" eType="ecore:EDataType
> http://www.eclipse.org/emf/2002/Ecore#//EString"/>
> <eStructuralFeatures xsi:type="ecore:EAttribute" name="value"
> lowerBound="1" eType="ecore:EDataType
> http://www.eclipse.org/emf/2002/Ecore#//EString"/>
> </eClassifiers>
> </ecore:EPackage>
>
Re: [QVTo] How to avoid mapping the same object twice? [message #550558 is a reply to message #550550] Fri, 30 July 2010 19:23 Go to previous messageGo to next message
Ryan is currently offline RyanFriend
Messages: 74
Registered: July 2009
Location: Indiana
Member
Edward Willink wrote on Fri, 30 July 2010 14:38
Hi Ryan

All the created elements that have no container are contained by the root.

Mapping compositions is easy. Mapping aggregations is much harder.
You'll probably need something like this:
mapping Base::TemplateBindingCS::decorateTemplateBinding(inout dict : 
Dict(String,Pivot::Element)) : Pivot::TemplateBinding {
	init {
		result := self.resolveone(Pivot::TemplateBinding);
		if result->isEmpty() then {		-- should never happen
			result := invalid;
		}
		else if result.parameterSubstitution->isEmpty() then {
			result.parameterSubstitution := self.ownedParameterSubstitution->map 
decorateTemplateParameterSubstitution(dict);
		}
		endif endif;
	}
}

To cope with the three cases and workaround the lack of return support.

Target does not exist and needs creating.
Target exists but is not configured.
Target already exists and needs configuring.

You are currently creating new targets for the last two cases.

Regards

Ed Willink



Thanks Ed for the reply. I guess I don't quite follow. It would make sense that the destination ItemData class had not been created/configured when the call to item2pairs() was called (because they all end up at the root), but the output file does have each ItemData and their name is set. I guess I don't understand what I need to do different. I thought that a mapping implicitly created the result object after the init section but before the population section. I even tried explicitly creating the ItemData in the init, but that didn't work either. Do I need to do something to initialize the collection "data" in an ItemData class?

mapping ItemList::itemList2ItemData() : ItemData {
	init {
		self.nextColorIndex := 0;
		self.nextItemIndex := 0;
		result := object Model2::ItemData{};
	}
	name := self.name + 'data';
	data := self.items.map item2Pairs(self)->asOrderedSet();
}
Re: [QVTo] How to avoid mapping the same object twice? [message #550560 is a reply to message #550558] Fri, 30 July 2010 19:37 Go to previous messageGo to next message
Ryan is currently offline RyanFriend
Messages: 74
Registered: July 2009
Location: Indiana
Member
Well, I got it working. After posting about init and population, I realized I just needed to move the creation of the result object into the init section on my mappings:
mapping Color::color2Pairs(list : ItemList) : Collection(Pair) {
	init {
		result := Sequence {
			object Pair {
				name := self.color2PairAttributeName(list, 'red');
				value := self.red.toString();
			},
			object Pair {
				name := self.color2PairAttributeName(list, 'green');
				value := self.green.toString();
			},
			object Pair {
				name := self.color2PairAttributeName(list, 'blue');
				value := self.blue.toString();
			}
		}
	}
}

mapping Item::item2Pairs(list : ItemList) : Collection(Pair) {
	init {
		result := Sequence {
			object Pair {
				name := self.item2PairAttributeName(list, 'name');
				value := self.itemName;
			},
			object Pair {
				name := self.item2PairAttributeName(list, 'color');
				value := self.itemColor.map color2Index(list).indexValue.toString();
			}
		};
		result += self.itemColor.map color2Pairs(list);
	}
}


Now the second model is created with all pairs below the intended itemdata list, and and each color is mapped only once for each itemdata list, and the index saved. Thanks to all who helped me arrive at this solution. A deadline was looming and had I not got it working by today, I would have had to code it in java.

Edit:
Even though this works, I'm a bit confused as to why the second time
result += self.itemColor.map color2Pairs(list);
is called (with the same color and list parameters), even though the mapping doesn't take place, shouldn't the original set of pairs be returned from the first time the mapping took place? I guess I would assume I should have two sets of identical color[0].red .... if two items were associated with red.


Edit2:
Examining the qvtotrace file for a transform shows that for an item that has a color that has already been mapped, the mapping for that color is not called, but the result of the item mapping still has 5 pairs in the collection, but the resultant output model only has the 2 for the item, not the additional 3 for the (duplicate) color. Is the qvto transform smart enough to know that the color pairs have already been added to the list of pairs and skips adding them?

[Updated on: Fri, 30 July 2010 20:12]

Report message to a moderator

Re: [QVTo] How to avoid mapping the same object twice? [message #550695 is a reply to message #550533] Wed, 04 August 2010 07:33 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: koen.yskout.cs.kuleuven.be

Ryan,

Note that item2Pairs returns a collection of Pairs for each item, and
you call the mapping for each item in the itemlist. You thus end up with
a collection of a collection of pairs, which you need to flatten to be
able to add them to the data as a single collection of pairs. (I made
exactly the same error when creating the sample code at first, giving
the same strange result ;))

Koen


On 30/07/10 19:04, Ryan wrote:
> Thanks Koen for the sample code. I understand better now how to get
> qvto to do what I want it to do. I got it to pretty much work how I
> want, but can't seem to figure out why all the pairs end up at the root
> of model 2 instead of within each ItemData. The mapping
> itemList2itemData() stores the pairs returned from item2pairs() in it's
> data field, but when this gets run, they end up as children of the root
> of the model. Any thoughs? I have a feeling I'm overlooking something
> simple here.
>
> Here is the modified code:
>
> modeltype Model1 "strict" uses "http://org.example/models/1.0/model1";
> modeltype Model2 "strict" uses "http://org.example/models/1.0/model2";
>
> transformation First2Second(in model1 : Model1, out model2 : Model2);
>
> // Wrapper object for an integer
> intermediate class Index {
> indexValue : Integer;
> }
> intermediate property ItemList::nextColorIndex : Integer;
> intermediate property ItemList::nextItemIndex : Integer;
>
> main() {
> model1.objectsOfType(Model1Root)->map first2Second();
> }
>
> mapping Model1::Model1Root::first2Second() : Model2::Model2Root {
> dataLists := self.products.map itemList2ItemData()->asOrderedSet();
> }
>
> mapping ItemList::itemList2ItemData() : ItemData {
> init {
> self.nextColorIndex := 0;
> self.nextItemIndex := 0;
> }
> name := self.name + 'data';
> data := self.items.map item2Pairs(self)->asOrderedSet();
> }
>
> // Map a color to an index in the context of a given ItemList.
> // Always returns same Index object when called using the same
> (Color,ItemList) pair.
> mapping Color::color2Index(list : ItemList) : Index {
> indexValue := list.nextColorIndex;
> list.nextColorIndex := list.nextColorIndex + 1;
> }
>
> mapping Item::item2Index(list : ItemList) : Index {
> indexValue := list.nextItemIndex;
> list.nextItemIndex := list.nextItemIndex + 1;
> }
>
> helper Color::color2PairAttributeName(list: ItemList, attribute :
> String) : String {
> var index := self.map color2Index(list).indexValue;
> return indexedNameAttribute('color', index, attribute);
> }
>
> helper Item::item2PairAttributeName(list: ItemList, attribute :
> String) : String {
> var index := self.map item2Index(list).indexValue;
> return indexedNameAttribute('item', index, attribute);
> }
>
> helper indexedNameAttribute(name : String, index : Integer, attribute
> : String) : String {
> return name + '[' + index.toString() + '].' + attribute;
> }
>
> mapping Color::color2Pairs(list : ItemList) : Sequence(Pair) {
> result := Sequence {
> object Pair {
> name := self.color2PairAttributeName(list, 'red');
> value := self.red.toString();
> },
> object Pair {
> name := self.color2PairAttributeName(list, 'green');
> value := self.green.toString();
> },
> object Pair {
> name := self.color2PairAttributeName(list, 'blue');
> value := self.blue.toString();
> }
> }
> }
>
> mapping Item::item2Pairs(list : ItemList) : Sequence(Pair) {
> result := Sequence {
> object Pair {
> name := self.item2PairAttributeName(list, 'name');
> value := self.itemName;
> },
> object Pair {
> name := self.item2PairAttributeName(list, 'color');
> value := self.itemColor.map
> color2Index(list).indexValue.toString();
> }
> };
> result += self.itemColor.map color2Pairs(list)->asOrderedSet();
> }
>
> And I couldn't figure out how to attach files to this post, so here are
> my Model1.ecore
> <?xml version="1.0" encoding="UTF-8"?>
> <ecore:EPackage xmi:version="2.0"
> xmlns:xmi="http://www.omg.org/XMI"
> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
> xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="model1"
> nsURI="http://org.example/models/1.0/model1"
> nsPrefix="org.example.models">
> <eClassifiers xsi:type="ecore:EClass" name="Color">
> <eStructuralFeatures xsi:type="ecore:EAttribute" name="red"
> lowerBound="1" eType="ecore:EDataType
> http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
> <eStructuralFeatures xsi:type="ecore:EAttribute" name="green"
> lowerBound="1" eType="ecore:EDataType
> http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
> <eStructuralFeatures xsi:type="ecore:EAttribute" name="blue"
> lowerBound="1" eType="ecore:EDataType
> http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
> <eStructuralFeatures xsi:type="ecore:EAttribute" name="name"
> lowerBound="1" eType="ecore:EDataType
> http://www.eclipse.org/emf/2002/Ecore#//EString"/>
> </eClassifiers>
> <eClassifiers xsi:type="ecore:EClass" name="Item">
> <eStructuralFeatures xsi:type="ecore:EAttribute" name="itemName"
> lowerBound="1"
> eType="ecore:EDataType
> http://www.eclipse.org/emf/2002/Ecore#//EString"/>
> <eStructuralFeatures xsi:type="ecore:EReference" name="itemColor"
> lowerBound="1"
> eType="#//Color"/>
> </eClassifiers>
> <eClassifiers xsi:type="ecore:EClass" name="ColorList">
> <eStructuralFeatures xsi:type="ecore:EReference" name="colors"
> upperBound="-1"
> eType="#//Color" containment="true"/>
> </eClassifiers>
> <eClassifiers xsi:type="ecore:EClass" name="ItemList">
> <eStructuralFeatures xsi:type="ecore:EReference" name="items"
> upperBound="-1"
> eType="#//Item" containment="true"/>
> <eStructuralFeatures xsi:type="ecore:EAttribute" name="name"
> lowerBound="1" eType="ecore:EDataType
> http://www.eclipse.org/emf/2002/Ecore#//EString"/>
> </eClassifiers>
> <eClassifiers xsi:type="ecore:EClass" name="Model1Root">
> <eStructuralFeatures xsi:type="ecore:EReference" name="products"
> upperBound="-1"
> eType="#//ItemList" containment="true"/>
> <eStructuralFeatures xsi:type="ecore:EReference" name="colorData"
> lowerBound="1"
> eType="#//ColorList" containment="true"/>
> </eClassifiers>
> </ecore:EPackage>
>
>
> And my Model2.ecore:
> <?xml version="1.0" encoding="UTF-8"?>
> <ecore:EPackage xmi:version="2.0"
> xmlns:xmi="http://www.omg.org/XMI"
> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
> xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="model2"
> nsURI="http://org.example/models/1.0/model2"
> nsPrefix="org.example.models">
> <eClassifiers xsi:type="ecore:EClass" name="Model2Root">
> <eStructuralFeatures xsi:type="ecore:EReference" name="dataLists"
> upperBound="-1"
> eType="#//ItemData" containment="true"/>
> </eClassifiers>
> <eClassifiers xsi:type="ecore:EClass" name="ItemData">
> <eStructuralFeatures xsi:type="ecore:EReference" name="data"
> upperBound="-1" eType="#//Pair"
> containment="true"/>
> <eStructuralFeatures xsi:type="ecore:EAttribute" name="name"
> lowerBound="1" eType="ecore:EDataType
> http://www.eclipse.org/emf/2002/Ecore#//EString"/>
> </eClassifiers>
> <eClassifiers xsi:type="ecore:EClass" name="Pair">
> <eStructuralFeatures xsi:type="ecore:EAttribute" name="name"
> lowerBound="1" eType="ecore:EDataType
> http://www.eclipse.org/emf/2002/Ecore#//EString"/>
> <eStructuralFeatures xsi:type="ecore:EAttribute" name="value"
> lowerBound="1" eType="ecore:EDataType
> http://www.eclipse.org/emf/2002/Ecore#//EString"/>
> </eClassifiers>
> </ecore:EPackage>
>
Re: [QVTo] How to avoid mapping the same object twice? [message #550700 is a reply to message #550695] Wed, 04 August 2010 07:40 Go to previous messageGo to next message
Eclipse UserFriend
Originally posted by: koen.yskout.cs.kuleuven.be

Oops, never mind...
I see that my explanation is incorrect (the QVT parser catches the
faulty assignment, as should be expected), and you found the cause of
your result (which was another error I also made at some point, hence
the confusion :p)

Koen


On 04/08/10 09:33, Koen Yskout wrote:
> Ryan,
>
> Note that item2Pairs returns a collection of Pairs for each item, and
> you call the mapping for each item in the itemlist. You thus end up with
> a collection of a collection of pairs, which you need to flatten to be
> able to add them to the data as a single collection of pairs. (I made
> exactly the same error when creating the sample code at first, giving
> the same strange result ;))
>
> Koen
>
>
> On 30/07/10 19:04, Ryan wrote:
>> Thanks Koen for the sample code. I understand better now how to get
>> qvto to do what I want it to do. I got it to pretty much work how I
>> want, but can't seem to figure out why all the pairs end up at the root
>> of model 2 instead of within each ItemData. The mapping
>> itemList2itemData() stores the pairs returned from item2pairs() in it's
>> data field, but when this gets run, they end up as children of the root
>> of the model. Any thoughs? I have a feeling I'm overlooking something
>> simple here.
>>
>> Here is the modified code:
>>
>> modeltype Model1 "strict" uses "http://org.example/models/1.0/model1";
>> modeltype Model2 "strict" uses "http://org.example/models/1.0/model2";
>>
>> transformation First2Second(in model1 : Model1, out model2 : Model2);
>>
>> // Wrapper object for an integer
>> intermediate class Index {
>> indexValue : Integer;
>> }
>> intermediate property ItemList::nextColorIndex : Integer;
>> intermediate property ItemList::nextItemIndex : Integer;
>>
>> main() {
>> model1.objectsOfType(Model1Root)->map first2Second();
>> }
>>
>> mapping Model1::Model1Root::first2Second() : Model2::Model2Root {
>> dataLists := self.products.map itemList2ItemData()->asOrderedSet();
>> }
>>
>> mapping ItemList::itemList2ItemData() : ItemData {
>> init {
>> self.nextColorIndex := 0;
>> self.nextItemIndex := 0;
>> }
>> name := self.name + 'data';
>> data := self.items.map item2Pairs(self)->asOrderedSet();
>> }
>>
>> // Map a color to an index in the context of a given ItemList.
>> // Always returns same Index object when called using the same
>> (Color,ItemList) pair.
>> mapping Color::color2Index(list : ItemList) : Index {
>> indexValue := list.nextColorIndex;
>> list.nextColorIndex := list.nextColorIndex + 1;
>> }
>>
>> mapping Item::item2Index(list : ItemList) : Index {
>> indexValue := list.nextItemIndex;
>> list.nextItemIndex := list.nextItemIndex + 1;
>> }
>>
>> helper Color::color2PairAttributeName(list: ItemList, attribute :
>> String) : String {
>> var index := self.map color2Index(list).indexValue;
>> return indexedNameAttribute('color', index, attribute);
>> }
>>
>> helper Item::item2PairAttributeName(list: ItemList, attribute :
>> String) : String {
>> var index := self.map item2Index(list).indexValue;
>> return indexedNameAttribute('item', index, attribute);
>> }
>>
>> helper indexedNameAttribute(name : String, index : Integer, attribute
>> : String) : String {
>> return name + '[' + index.toString() + '].' + attribute;
>> }
>>
>> mapping Color::color2Pairs(list : ItemList) : Sequence(Pair) {
>> result := Sequence {
>> object Pair {
>> name := self.color2PairAttributeName(list, 'red');
>> value := self.red.toString();
>> },
>> object Pair {
>> name := self.color2PairAttributeName(list, 'green');
>> value := self.green.toString();
>> },
>> object Pair {
>> name := self.color2PairAttributeName(list, 'blue');
>> value := self.blue.toString();
>> }
>> }
>> }
>>
>> mapping Item::item2Pairs(list : ItemList) : Sequence(Pair) {
>> result := Sequence {
>> object Pair {
>> name := self.item2PairAttributeName(list, 'name');
>> value := self.itemName;
>> },
>> object Pair {
>> name := self.item2PairAttributeName(list, 'color');
>> value := self.itemColor.map
>> color2Index(list).indexValue.toString();
>> }
>> };
>> result += self.itemColor.map color2Pairs(list)->asOrderedSet();
>> }
>>
>> And I couldn't figure out how to attach files to this post, so here are
>> my Model1.ecore
>> <?xml version="1.0" encoding="UTF-8"?>
>> <ecore:EPackage xmi:version="2.0"
>> xmlns:xmi="http://www.omg.org/XMI"
>> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>> xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="model1"
>> nsURI="http://org.example/models/1.0/model1"
>> nsPrefix="org.example.models">
>> <eClassifiers xsi:type="ecore:EClass" name="Color">
>> <eStructuralFeatures xsi:type="ecore:EAttribute" name="red"
>> lowerBound="1" eType="ecore:EDataType
>> http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
>> <eStructuralFeatures xsi:type="ecore:EAttribute" name="green"
>> lowerBound="1" eType="ecore:EDataType
>> http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
>> <eStructuralFeatures xsi:type="ecore:EAttribute" name="blue"
>> lowerBound="1" eType="ecore:EDataType
>> http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
>> <eStructuralFeatures xsi:type="ecore:EAttribute" name="name"
>> lowerBound="1" eType="ecore:EDataType
>> http://www.eclipse.org/emf/2002/Ecore#//EString"/>
>> </eClassifiers>
>> <eClassifiers xsi:type="ecore:EClass" name="Item">
>> <eStructuralFeatures xsi:type="ecore:EAttribute" name="itemName"
>> lowerBound="1"
>> eType="ecore:EDataType
>> http://www.eclipse.org/emf/2002/Ecore#//EString"/>
>> <eStructuralFeatures xsi:type="ecore:EReference" name="itemColor"
>> lowerBound="1"
>> eType="#//Color"/>
>> </eClassifiers>
>> <eClassifiers xsi:type="ecore:EClass" name="ColorList">
>> <eStructuralFeatures xsi:type="ecore:EReference" name="colors"
>> upperBound="-1"
>> eType="#//Color" containment="true"/>
>> </eClassifiers>
>> <eClassifiers xsi:type="ecore:EClass" name="ItemList">
>> <eStructuralFeatures xsi:type="ecore:EReference" name="items"
>> upperBound="-1"
>> eType="#//Item" containment="true"/>
>> <eStructuralFeatures xsi:type="ecore:EAttribute" name="name"
>> lowerBound="1" eType="ecore:EDataType
>> http://www.eclipse.org/emf/2002/Ecore#//EString"/>
>> </eClassifiers>
>> <eClassifiers xsi:type="ecore:EClass" name="Model1Root">
>> <eStructuralFeatures xsi:type="ecore:EReference" name="products"
>> upperBound="-1"
>> eType="#//ItemList" containment="true"/>
>> <eStructuralFeatures xsi:type="ecore:EReference" name="colorData"
>> lowerBound="1"
>> eType="#//ColorList" containment="true"/>
>> </eClassifiers>
>> </ecore:EPackage>
>>
>>
>> And my Model2.ecore:
>> <?xml version="1.0" encoding="UTF-8"?>
>> <ecore:EPackage xmi:version="2.0"
>> xmlns:xmi="http://www.omg.org/XMI"
>> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>> xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="model2"
>> nsURI="http://org.example/models/1.0/model2"
>> nsPrefix="org.example.models">
>> <eClassifiers xsi:type="ecore:EClass" name="Model2Root">
>> <eStructuralFeatures xsi:type="ecore:EReference" name="dataLists"
>> upperBound="-1"
>> eType="#//ItemData" containment="true"/>
>> </eClassifiers>
>> <eClassifiers xsi:type="ecore:EClass" name="ItemData">
>> <eStructuralFeatures xsi:type="ecore:EReference" name="data"
>> upperBound="-1" eType="#//Pair"
>> containment="true"/>
>> <eStructuralFeatures xsi:type="ecore:EAttribute" name="name"
>> lowerBound="1" eType="ecore:EDataType
>> http://www.eclipse.org/emf/2002/Ecore#//EString"/>
>> </eClassifiers>
>> <eClassifiers xsi:type="ecore:EClass" name="Pair">
>> <eStructuralFeatures xsi:type="ecore:EAttribute" name="name"
>> lowerBound="1" eType="ecore:EDataType
>> http://www.eclipse.org/emf/2002/Ecore#//EString"/>
>> <eStructuralFeatures xsi:type="ecore:EAttribute" name="value"
>> lowerBound="1" eType="ecore:EDataType
>> http://www.eclipse.org/emf/2002/Ecore#//EString"/>
>> </eClassifiers>
>> </ecore:EPackage>
>>
>
Re: [QVTo] How to attach intermediate data that is valid only within the scope of a mapping? [message #550845 is a reply to message #550054] Wed, 04 August 2010 13:44 Go to previous messageGo to next message
Ryan is currently offline RyanFriend
Messages: 74
Registered: July 2009
Location: Indiana
Member
Thanks Koen for following up on this thread.

My last question was why no duplicates ended up in the list, even though the qvto trace files show that there should be (based on the return from each mapping). The answer to that is that each many mapping in the ecore model is by default set to ordered and unique, which make the ocl representation an orderedset that doesn't allow duplicates.

However, I've got one other question about how the init section works, basically, why do the assignment statements for the pairs need to go in the init section, isn't that populating the result object (which seems like it should go in the population section).
Re: [QVTo] How to attach intermediate data that is valid only within the scope of a mapping? [message #550929 is a reply to message #550845] Wed, 04 August 2010 15:48 Go to previous message
Eclipse UserFriend
Originally posted by: koen.yskout.cs.kuleuven.be

If you want to include only the colors from the list that are actually
used by your items into the ItemData, you can also do something like the
following:

// map used colors only
data := self.items->itemColor->asOrderedSet()->color2Pairs(self).flatten();
// map items
data += self.items->item2Pairs(self).flatten();

It will select the colors from the items, weed out duplicates by
converting it to a set, and then doing the conversion to pairs for each
color.


As far as I know (but people that know the QVT spec better might have a
better answer), in the population section you set values for the
attributes of the object that you return.

Returning a collection is something special, because Collection is not
really a class from one of the models, but a built-in type. Therefore
you can't set its contents in the population section, because it doesn't
have user-settable attributes. (Imagine for a moment a collection would
have a 'elements' attribute, then 'elements := self.map someMapping'
would make more sense in the population section, I guess).

I have the impression that QVT became quite liberal with its syntax
since version 2, so a lot more is allowed now than before, making the
distinction between the init section and the population section more
difficult to notice now than before, except in some cases like this.

Koen


On 04/08/10 15:44, Ryan wrote:
> Thanks Koen for following up on this thread.
>
> My last question was why no duplicates ended up in the list, even though
> the qvto trace files show that there should be (based on the return from
> each mapping). The answer to that is that each many mapping in the
> ecore model is by default set to ordered and unique, which make the ocl
> representation an orderedset that doesn't allow duplicates.
>
> However, I've got one other question about how the init section works,
> basically, why do the assignment statements for the pairs need to go in
> the init section, isn't that populating the result object (which seems
> like it should go in the population section).
Previous Topic:[ATL] Ant Task: set "Is metametamodel" option
Next Topic:[ATL] Using profile with ATL
Goto Forum:
  


Current Time: Mon May 17 11:08:00 GMT 2021

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

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

Back to the top