Home » Modeling » Epsilon » [ETL] How to deal with removing circular references
[ETL] How to deal with removing circular references [message #468488] |
Wed, 05 August 2009 16:10 |
Eclipse User |
|
|
|
Originally posted by: d.clowes.lboro.ac.uk
Hello all,
Is anyone able to provide some guidence on this?
I have a class which contains(0..*) subclasses which then contains (0..*)
instances of itself i.e.
class c1 { val c2[*]#parent contains;}
class c2 { val c2[*] contains; ref c1#contains parent}
I need to transform this to a new model where c2 can not contain
instances. i.e. all instances in c2.contains need to be stored under
c1.contains.
The actual model is more detailed than this but this is the bit I'm stuck
on. I tried:
@lazy
rule NumberedParagraph
transform p1 : DocumentModel!ParagraphType
to p2:DocumentStructure!NumberedParagraph, t2 : DocumentStructure!Text{
guard : p1.numbering.isDefined() and p1.numbering <> ''
p2.numbering := p1.numbering;
t2.text := p1.text;
p2.text.add(t2);
for (z in p1.group){
p2.parent.children.add(z.getValue().equivalent());
}
}
But p2.parent does not exist yet. Anyone have any pointers to what I
should try next. Many thanks.
Darren
|
|
|
Re: [ETL] How to deal with removing circular references [message #478365 is a reply to message #468488] |
Thu, 06 August 2009 09:31 |
Louis Rose Messages: 440 Registered: July 2009 Location: York, United Kingdom |
Senior Member |
|
|
Hi Darren,
Reply hidden below :)
Darren Clowes wrote:
> Hello all,
>
> Is anyone able to provide some guidence on this?
>
> I have a class which contains(0..*) subclasses which then contains
> (0..*) instances of itself i.e.
>
> class c1 { val c2[*]#parent contains;}
> class c2 { val c2[*] contains; ref c1#contains parent}
>
> I need to transform this to a new model where c2 can not contain
> instances. i.e. all instances in c2.contains need to be stored under
> c1.contains.
Ok, this seems a little odd to me. Consider the following model, which
instantiates the metamodel described above:
top, an instance of c1, contains:
foo, an instance of c2.
bar, an instance of c2, which contains:
baz an instance of c2.
The parent of foo is top (opposite of contains). The parent of bar is
top (opposite of contains). The parent of baz is null, as it is not
contained in an instance of c1 (but in an instance of c2).
Consequently, transforming model elements contained in instances of c2
will be tricky (though not impossible). A restructuring of the metamodel
fixes the null parent problem. Is it possible to restructure the
metamodel like so:
class c1 {
val c2[*]#parent contains;
}
class c2 extends c1 {
ref c1#contains parent;
}
>
> The actual model is more detailed than this but this is the bit I'm
> stuck on. I tried:
>
> @lazy
> rule NumberedParagraph
> transform p1 : DocumentModel!ParagraphType
> to p2:DocumentStructure!NumberedParagraph, t2 : DocumentStructure!Text{
> guard : p1.numbering.isDefined() and p1.numbering <> ''
> p2.numbering := p1.numbering;
> t2.text := p1.text;
> p2.text.add(t2);
> for (z in p1.group){
> p2.parent.children.add(z.getValue().equivalent());
> }
> }
If the above restructuring isn't possible, the following transformation
should work:
rule Container2Container
transform s : Source!c1
to t : Target!c1 {
-- transform other features, e.g:
-- t.name := s.name;
}
rule Content2Content
transform s : Source!c2
to t : Target!c2 {
t.parent := s.findParent().equivalent();
}
operation Source!c2 findParent() : Source!c1 {
if (self.parent.isUndefined()) {
return self.eContainer().findParent();
}
return self.parent;
}
The findParent operation is defined for instances of c2 in the source
metamodel. It uses recursion to locate the containing c1 element:
- if self.parent is non-null, the parent is simply returned (the base case)
- otherwise, we use the eContainer() method to determine the object that
contains this instance of c2, and recursively invoke findParent() (the
recursive case)
The use of eContainer() is _A Bad Thing_, it is specific to EMF
metamodels and can only be invoking on EObjects.
Finally, note the use of the built-in operation equivalent() in the body
of the Content2Content rule. equivalent() will convert from an instance
of the source model to an instance of the target model using the
transformation rules defined. In this case, equivalent() is used to
convert from an instance of Source!c1 to an instance of Target!c1. Hence
the need for the first rule.
Cheers,
Louis.
|
|
|
Re: [ETL] How to deal with removing circular references [message #572547 is a reply to message #468488] |
Thu, 06 August 2009 09:31 |
Louis Rose Messages: 440 Registered: July 2009 Location: York, United Kingdom |
Senior Member |
|
|
Hi Darren,
Reply hidden below :)
Darren Clowes wrote:
> Hello all,
>
> Is anyone able to provide some guidence on this?
>
> I have a class which contains(0..*) subclasses which then contains
> (0..*) instances of itself i.e.
>
> class c1 { val c2[*]#parent contains;}
> class c2 { val c2[*] contains; ref c1#contains parent}
>
> I need to transform this to a new model where c2 can not contain
> instances. i.e. all instances in c2.contains need to be stored under
> c1.contains.
Ok, this seems a little odd to me. Consider the following model, which
instantiates the metamodel described above:
top, an instance of c1, contains:
foo, an instance of c2.
bar, an instance of c2, which contains:
baz an instance of c2.
The parent of foo is top (opposite of contains). The parent of bar is
top (opposite of contains). The parent of baz is null, as it is not
contained in an instance of c1 (but in an instance of c2).
Consequently, transforming model elements contained in instances of c2
will be tricky (though not impossible). A restructuring of the metamodel
fixes the null parent problem. Is it possible to restructure the
metamodel like so:
class c1 {
val c2[*]#parent contains;
}
class c2 extends c1 {
ref c1#contains parent;
}
>
> The actual model is more detailed than this but this is the bit I'm
> stuck on. I tried:
>
> @lazy
> rule NumberedParagraph
> transform p1 : DocumentModel!ParagraphType
> to p2:DocumentStructure!NumberedParagraph, t2 : DocumentStructure!Text{
> guard : p1.numbering.isDefined() and p1.numbering <> ''
> p2.numbering := p1.numbering;
> t2.text := p1.text;
> p2.text.add(t2);
> for (z in p1.group){
> p2.parent.children.add(z.getValue().equivalent());
> }
> }
If the above restructuring isn't possible, the following transformation
should work:
rule Container2Container
transform s : Source!c1
to t : Target!c1 {
-- transform other features, e.g:
-- t.name := s.name;
}
rule Content2Content
transform s : Source!c2
to t : Target!c2 {
t.parent := s.findParent().equivalent();
}
operation Source!c2 findParent() : Source!c1 {
if (self.parent.isUndefined()) {
return self.eContainer().findParent();
}
return self.parent;
}
The findParent operation is defined for instances of c2 in the source
metamodel. It uses recursion to locate the containing c1 element:
- if self.parent is non-null, the parent is simply returned (the base case)
- otherwise, we use the eContainer() method to determine the object that
contains this instance of c2, and recursively invoke findParent() (the
recursive case)
The use of eContainer() is _A Bad Thing_, it is specific to EMF
metamodels and can only be invoking on EObjects.
Finally, note the use of the built-in operation equivalent() in the body
of the Content2Content rule. equivalent() will convert from an instance
of the source model to an instance of the target model using the
transformation rules defined. In this case, equivalent() is used to
convert from an instance of Source!c1 to an instance of Target!c1. Hence
the need for the first rule.
Cheers,
Louis.
|
|
|
Goto Forum:
Current Time: Sat May 04 15:44:25 GMT 2024
Powered by FUDForum. Page generated in 0.02557 seconds
|