Search code examples
documentmetafile

EMF alternate child references


As example I want to model in EMF a word-document:

This would be my metamodel:

document
  - table (0..*)
  - paragraph (0..*)

The problem here is that the model would be very linear:

document
  - table_1
  - table_2
  - table_3
  - paragraph_1

There is no possibility to insert a paragraph between two tables (table_1 and table_2).

My solution was to model the metamodel in another way:

document
  - (abstract) documentChild (0..*)
table inherit documentChild
paragraph inherit documentChild

This seems for me not optimal. Is there another way to solve this problem in EMF?


Solution

  • This is exactly a use-case for "Feature maps" in EMF.

    You want to combine multiple types of objects into a single ordered list and then access individual types using separate references.

    So, I created a minimal meta-model that shows how a Document can contain a mixture of Table and Paragraph instances.

    enter image description here

    The trick is that all the instances are actually located in the elements attribute (EFeatureMapEntry data type). Then, the tables and paragraphs references are just projections of the elements container. As you can see in the following figure, the instances are stored in a correct order.

    enter image description here

    It is a bit tricky to properly set up all the properties of EMF classes. Especially

    volatile="true"
    transient="true"
    derived="true"
    containment="true"
    

    Therefore, I'm listing the complete XMI content of the meta-model here:

    <?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="doc" nsURI="doc" nsPrefix="doc">
      <eClassifiers xsi:type="ecore:EClass" name="Table">
        <eStructuralFeatures xsi:type="ecore:EAttribute" name="id" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
      </eClassifiers>
      <eClassifiers xsi:type="ecore:EClass" name="Paragraph">
        <eStructuralFeatures xsi:type="ecore:EAttribute" name="id" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
      </eClassifiers>
      <eClassifiers xsi:type="ecore:EClass" name="Document">
        <eStructuralFeatures xsi:type="ecore:EReference" name="tables" ordered="false"
            upperBound="-1" eType="#//Table" volatile="true" transient="true" derived="true"
            containment="true">
          <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData">
            <details key="group" value="#elements"/>
          </eAnnotations>
        </eStructuralFeatures>
        <eStructuralFeatures xsi:type="ecore:EReference" name="paragraphs" ordered="false"
            upperBound="-1" eType="#//Paragraph" volatile="true" transient="true" derived="true"
            containment="true">
          <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData">
            <details key="group" value="#elements"/>
          </eAnnotations>
        </eStructuralFeatures>
        <eStructuralFeatures xsi:type="ecore:EAttribute" name="elements" upperBound="-1"
            eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFeatureMapEntry">
          <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData">
            <details key="kind" value="group"/>
          </eAnnotations>
        </eStructuralFeatures>
      </eClassifiers>
    </ecore:EPackage>