diff --git a/src/main/jastadd/XMI/XMIWriter.jadd b/src/main/jastadd/XMI/XMIWriter.jadd
new file mode 100644
index 0000000000000000000000000000000000000000..4096a537a60ef290e36e44c4bfb5fcbd07d102d9
--- /dev/null
+++ b/src/main/jastadd/XMI/XMIWriter.jadd
@@ -0,0 +1,84 @@
+aspect XMIWriter {
+
+  public static String ASTNode.indentString(int n) {
+    char[] chars = new char[2*n];
+    java.util.Arrays.fill(chars, ' ');
+    return new String(chars);
+  }
+
+  public void EPackage.writeXMI(StringBuilder b) {
+    b.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+    this.writeXMI(b, null, 0);
+  }
+
+  void ASTNode.startXMIElement(StringBuilder b, String type, String context) {
+    if (context == null) {
+      // we have a top-level element that is not contained in anything
+      b.append(type).append(" 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\"");
+    } else {
+      b.append(context).append(" xsi:type=\"").append(type).append("\"");
+    }
+  }
+
+  void ASTNode.endXMIElement(StringBuilder b, String type, String context) {
+    b.append((context == null) ? type : context);
+  }
+
+  void EPackage.writeXMI(StringBuilder b, String context, int indentationLevel) {
+    // opening tag
+    b.append(indentString(indentationLevel)).append("<");
+    startXMIElement(b, "ecore:EPackage", context);
+    b.append(" name=\"").append(getName()).append("\"")
+      .append(" nsURI=\"").append(getNsURI()).append("\"")
+      .append(" nsPrefix=\"").append(getNsPrefix()).append("\"")
+      .append(">\n");
+
+
+    for (EClassifier eClassifier : getEClassifierList()) {
+      eClassifier.writeXMI(b, "eClassifiers", indentationLevel + 1);
+    }
+    for (EPackage eSubpackage : getESubPackageList()) {
+      eSubpackage.writeXMI(b, "eSubpackages", indentationLevel + 1);
+    }
+
+    // closing tag
+    b.append(indentString(indentationLevel)).append("</");
+    endXMIElement(b, "ecore:EPackage", context);
+    b.append(">\n");
+  }
+
+  abstract void EClassifier.writeXMI(StringBuilder b, String context, int indentationLevel);
+
+  void EClass.writeXMI(StringBuilder b, String context, int indentationLevel) {
+    b.append(indentString(indentationLevel)).append("<");
+    startXMIElement(b, "ecore:EClass", context);
+    // attributes
+    b.append(" name=\"").append(getName()).append("\"");
+
+    b.append(">\n");
+    // child nodes
+
+    // closing tag
+    b.append(indentString(indentationLevel)).append("</");
+    endXMIElement(b, "ecore:EPackage", context);
+    b.append(">\n");
+  }
+
+  void EDataType.writeXMI(StringBuilder b, String context, int indentationLevel) {
+    b.append(indentString(indentationLevel)).append("<");
+    startXMIElement(b, "ecore:EDataType", context);
+    // attributes
+    b.append(" name=\"").append(getName()).append("\"");
+
+    b.append(">\n");
+    // child nodes
+
+    // closing tag
+    b.append(indentString(indentationLevel)).append("</");
+    endXMIElement(b, "ecore:EPackage", context);
+    b.append(">\n");
+  }
+}
diff --git a/src/main/jastadd/ecore.relast b/src/main/jastadd/ecore.relast
index db51685be5146d365e220cc9c995d614aa4fa2ac..f03a19a331f43e12098574f511500fa95440e1c6 100644
--- a/src/main/jastadd/ecore.relast
+++ b/src/main/jastadd/ecore.relast
@@ -1,6 +1,6 @@
 
 // root
-EPackage : ENamedElement ::= EClassifier ESubPackage:EPackage* <NsURI:String> <NsPrefix:String>;
+EPackage : ENamedElement ::= EClassifier* ESubPackage:EPackage* <NsURI:String> <NsPrefix:String>;
 
 EObject;
 abstract EModelElement : EObject ::= EAnnotation*;
@@ -10,17 +10,17 @@ abstract ENamedElement : EModelElement ::= <Name:String>;
 EAnnotation : EModelElement ::= <Source:String> Detail:EStringToStringMapEntry*;
 
 
-abstract EClassifier : ENamedElement ::= ETypeParameter* <InstanceClassName:String> <InstanceClass:Class> <DefaultValue:Object>;
-EEnumLiteral : ENamedElement ::= <Value:int> <Instance:Enumerator>;
-abstract ETypedElement : ENamedElement ::= [EGenericType] <Ordered:boolean> <Unique:boolean> <LowerBound:int> <UpperBound:int> <Many:boolean> <Required:boolean>;
+abstract EClassifier : ENamedElement ::= ETypeParameter* <InstanceClassName:String>;
+EEnumLiteral : ENamedElement ::= <Value:int>;
+abstract ETypedElement : ENamedElement ::= [EGenericType] <Ordered:boolean> <Unique:boolean> <LowerBound:int> <UpperBound:int>;
 
 EClass : EClassifier ::= EStructuralFeature* EOperation* EGenericSuperType:EGenericType* <Abstract:boolean> <Interface:boolean>;
 EDataType : EClassifier;
 EEnum : EDataType ::= ELiteral:EEnumLiteral*;
 
-EStructuralFeature : ETypedElement ::= <Changeable:boolean> <Volatile:boolean> <Transient:boolean> <defaultValueLiteral:String> <DefaultValue:Object> <Unsettable:boolean> <Derived:boolean>;
+EStructuralFeature : ETypedElement ::= <Changeable:boolean> <Volatile:boolean> <Transient:boolean> <defaultValueLiteral:String> <Unsettable:boolean> <Derived:boolean>;
 EAttribute : EStructuralFeature ::= <ID:boolean>;
-EReference : EStructuralFeature ::= <Containment:boolean> <Container:boolean> <ResolveProxies:boolean>;
+EReference : EStructuralFeature ::= <Containment:boolean> <ResolveProxies:boolean>;
 EOperation : ETypedElement ::= GenericException:EGenericType* ETypeParameter* EParameter*;
 EParameter : ETypedElement;
 
@@ -29,25 +29,39 @@ EStringToStringMapEntry ::= <Key:String> <Value:String>;
 ETypeParameter : ENamedElement ::= EBounds:EGenericType*;
 EGenericType ::= [EUpperBound:EGenericType] [ELowerBound:EGenericType] [ETypeArguments:EGenericType];
 
-rel EFactory.EPackage <-> EPackage.EFactoryInstance;
 rel ETypedElement.EType -> EClassifier;
 rel EOperation.EExceptions* -> EClassifier;
-rel EClass.EAllOperations* -> EOperation;
-rel EClass.EAllStructuralFeatures* -> EStructuralFeature;
-rel EClass.EAllContainments* -> EReference;
-rel EClass.EAllReferences* -> EReference;
-rel EClass.EAllAttributes* -> EAttribute;
-rel EClass.EAttributes* -> EAttribute;
-rel EClass.EIDAttribute -> EAttribute;
 rel EClass.ESuperTypes* -> EClass;
-rel EClass.EAllSuperTypes* -> EClass;
-rel EClass.EAllGenericSuperTypes* -> EGenericType;
-
-rel EAttribute.EAttributeType -> EDataType;
-
+rel EReference.EOpposite? -> EReference;
 rel EAnnotation.References* -> EObject;
-
 rel ETypeParameter.GenericTypes* <-> EGenericType.ETypeParameter?;
 
-rel EGenericType.ERawType -> EClassifier;
+
 rel EGenericType.EClassifier? -> EClassifier;
+
+// transient stuff (the inverse directions of the containment relations are missing)
+
+// EClassifier : ENamedElement ::= <InstanceClass:Class> <DefaultValue:Object>;
+// EEnumLiteral : ENamedElement ::= <Instance:Enumerator>;
+// EReference : EStructuralFeature ::= <Container:boolean>;
+// EStructuralFeature : ETypedElement ::= <DefaultValue:Object> ;
+// abstract ETypedElement : ENamedElement ::= <Many:boolean> <Required:boolean>;
+
+// rel EAttribute.EAttributeType -> EDataType;
+
+// rel EClass.EAllAttributes* -> EAttribute;
+// rel EClass.EAllReferences* -> EReference;
+// rel EClass.EReferences* -> EReference;
+// rel EClass.EAttributes* -> EAttribute;
+// rel EClass.EAllStructuralFeatures* -> EStructuralFeature;
+// rel EClass.EAllContainments* -> EReference;
+// rel EClass.EAllSuperTypes* -> EClass;
+// rel EClass.EAllOperations* -> EOperation;
+// rel EClass.EAllGenericSuperTypes* -> EGenericType;
+// rel EClass.EIDAttribute -> EAttribute;
+
+// rel EReference.EReferenceType -> EClass;
+
+// rel EFactory.EPackage <-> EPackage.EFactoryInstance;
+
+// rel EGenericType.ERawType -> EClassifier;
diff --git a/src/main/java/de/tudresden/inf/st/e2j/parser/EcoreParser.java b/src/main/java/de/tudresden/inf/st/e2j/parser/EcoreParser.java
new file mode 100644
index 0000000000000000000000000000000000000000..33848110e7309a2780e7d8f5865b17e3f3056aa9
--- /dev/null
+++ b/src/main/java/de/tudresden/inf/st/e2j/parser/EcoreParser.java
@@ -0,0 +1,465 @@
+package de.tudresden.inf.st.e2j.parser;
+
+import de.tudresden.inf.st.e2j.jastadd.model.*;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.Namespace;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+public class EcoreParser {
+
+  private static final String XSI_NS = "http://www.w3.org/2001/XMLSchema-instance";
+  private static final QName XSI_TYPE = new QName(XSI_NS, "type");
+
+  private static Logger logger = LogManager.getLogger(EcoreParser.class);
+  private final XMLInputFactory factory = XMLInputFactory.newInstance();
+
+  public EObject parse(InputStream stream) throws XMIParseException {
+
+    try {
+      final XMLEventReader reader = factory.createXMLEventReader(stream);
+
+      // TODO there may be one or more elements in the root, if so, the top level element is called XMI (?)
+
+      while (reader.hasNext()) {
+        final XMLEvent event = reader.peek();
+
+        if (event.isStartDocument()) {
+          reader.nextEvent();
+        } else if (event.isStartElement()) {
+          StartElement root = event.asStartElement();
+
+          switch (root.getName().getLocalPart()) {
+            case "EPackage":
+              return parseEPackage(reader, Collections.EMPTY_MAP);
+            default:
+              throw new XMIParseException("Unable to parse root element " + root.getName().toString());
+          }
+        } else {
+          logger.error("the element is a {}", event.getEventType());
+          throw new XMIParseException("Element is not a start element!");
+        }
+
+      }
+    } catch (XMLStreamException e) {
+      throw new XMIParseException("Exception thrown while parsing XML!", e);
+    }
+
+    throw new XMIParseException("No contents in XMI file found!");
+  }
+
+  private Map<String, String> parseNameSpaces(StartElement element, Map<String, String> previousMap) {
+    Iterator namespaceIterator = element.getNamespaces();
+    if (!namespaceIterator.hasNext()) {
+      return previousMap;
+    }
+    Map<String, String> result = new HashMap<>(previousMap);
+    while (namespaceIterator.hasNext()) {
+      Namespace namespace = (Namespace) namespaceIterator.next();
+      logger.info("found Namespace {}:{}", namespace.getPrefix(), namespace.getNamespaceURI());
+      result.put(namespace.getPrefix(), namespace.getNamespaceURI());
+    }
+    return result;
+  }
+
+  private EPackage parseEPackage(final XMLEventReader reader, Map<String, String> nameSpaces) throws XMLStreamException {
+
+    EPackage ePackage = new EPackage();
+
+    // get all the properties out of the element
+    StartElement startElement = reader.nextEvent().asStartElement();
+
+    nameSpaces = parseNameSpaces(startElement, nameSpaces);
+
+    for (Iterator attributeIterator = startElement.getAttributes(); attributeIterator.hasNext(); ) {
+      Attribute attribute = (Attribute) attributeIterator.next();
+
+      switch (attribute.getName().getLocalPart()) {
+        case "nsURI":
+          ePackage.setNsURI(attribute.getValue());
+          break;
+        case "nsPrefix":
+          ePackage.setNsPrefix(attribute.getValue());
+          break;
+        case "name":
+          ePackage.setName(attribute.getValue());
+          break;
+        default:
+          logger.warn("ignoring attribute {}:{}", attribute.getName().getPrefix(), attribute.getName().getLocalPart());
+      }
+    }
+
+    // parse the contained elements
+    XMLEvent nextEvent = reader.peek();
+    while (true) {
+      if (nextEvent.isStartElement()) {
+        final StartElement nextElement = nextEvent.asStartElement();
+        switch (nextElement.getName().getLocalPart()) {
+          case "eClassifiers":
+            ePackage.addEClassifier(parseEClassifier(reader, nameSpaces));
+            break;
+          default:
+            logger.warn("ignoring element {}:{}", nextElement.getName().getPrefix(), nextElement.getName().getLocalPart());
+        }
+      } else if (nextEvent.isEndElement() && nextEvent.asEndElement().getName().equals(startElement.getName())) {
+        return ePackage;
+      } else {
+        // ignore all other events
+        if (nextEvent.getEventType() != XMLStreamConstants.CHARACTERS)
+          logger.warn("ignoring event {}: '{}'", nextEvent.getEventType(), nextEvent.toString().replace("\n", "\\n"));
+      }
+      reader.nextEvent();
+      nextEvent = reader.peek();
+    }
+  }
+
+  private EClassifier parseEClassifier(final XMLEventReader reader, Map<String, String> nameSpaces) throws XMLStreamException {
+    StartElement startElement = reader.peek().asStartElement();
+
+    EClassifier eClassifier;
+
+    final String type = startElement.getAttributeByName(XSI_TYPE).getValue();
+    switch (type) {
+      case "ecore:EClass":
+        eClassifier = parseEClass(reader, nameSpaces);
+        break;
+      case "ecore:EDataType":
+        eClassifier = parseEDataType(reader, nameSpaces);
+        break;
+      case "ecore:EEnum":
+        eClassifier = parseEEnum(reader, nameSpaces);
+        break;
+      default:
+        logger.error("Unknown subclass '{}' of EClassifier found", type);
+        throw new XMIParseException("Unknown subclass '" + type + "' of EClassifier found");
+    }
+
+    return eClassifier;
+
+  }
+
+  private EClassifier parseEClass(final XMLEventReader reader, Map<String, String> nameSpaces) throws XMLStreamException {
+
+    EClass eClass = new EClass();
+
+    // get all the properties out of the element
+    StartElement startElement = reader.nextEvent().asStartElement();
+
+    nameSpaces = parseNameSpaces(startElement, nameSpaces);
+
+    for (Iterator attributeIterator = startElement.getAttributes(); attributeIterator.hasNext(); ) {
+      Attribute attribute = (Attribute) attributeIterator.next();
+
+      if (attribute.getName().equals(XSI_TYPE)) {
+        if (!attribute.getValue().equals("ecore:EClass")) {
+          throw new XMIParseException("Expected ecore:EClass but found " + attribute.getValue(), attribute.getLocation());
+        }
+      } else {
+        switch (attribute.getName().getLocalPart()) {
+          // from ENamedElement
+          case "name":
+            eClass.setName(attribute.getValue());
+            break;
+          // from EClassifier
+          case "instanceClassName":
+            eClass.setInstanceClassName(attribute.getValue());
+            break;
+          case "instanceClass":
+            logger.warn("ignoring transient attribute 'instanceClass' with value '{}'", attribute.getValue());
+            break;
+          case "defaultValue":
+            logger.warn("ignoring transient attribute 'defaultValue' with value '{}'", attribute.getValue());
+            break;
+          case "ePackage":
+            logger.warn("ignoring parent relation 'ePackage' with value '{}'", attribute.getValue());
+            break;
+          // from EClass
+          case "abstract":
+            eClass.setAbstract(Boolean.valueOf(attribute.getValue()));
+            break;
+          case "interface":
+            eClass.setInterface(Boolean.valueOf(attribute.getValue()));
+            break;
+          case "eSuperTypes":
+            eClass.addESuperTypes(EClass.createRefDirection(attribute.getValue()));
+            break;
+          default:
+            logger.warn("ignoring attribute {}:{}", attribute.getName().getPrefix(), attribute.getName().getLocalPart());
+        }
+      }
+    }
+
+    // parse the contained elements
+    XMLEvent nextEvent = reader.peek();
+    while (true) {
+      if (nextEvent.isStartElement()) {
+        final StartElement nextElement = nextEvent.asStartElement();
+        switch (nextElement.getName().getLocalPart()) {
+          case "eTypeParameters":
+            eClass.addETypeParameter(parseETypeParameter(reader, nameSpaces));
+            break;
+          case "eStructuralFeatures":
+            eClass.addEStructuralFeature(parseEStructuralFeature(reader, nameSpaces));
+            break;
+          case "eOperations":
+            eClass.addEOperation(parseEOperation(reader, nameSpaces));
+            break;
+          case "eGenericSuperTypes":
+            eClass.addEGenericSuperType(parseEGenericSuperType(reader, nameSpaces));
+            break;
+          default:
+            logger.warn("ignoring element {}:{}", nextElement.getName().getPrefix(), nextElement.getName().getLocalPart());
+        }
+      } else if (nextEvent.isEndElement() && nextEvent.asEndElement().getName().equals(startElement.getName())) {
+        return eClass;
+      } else {
+        // ignore all other events
+        if (nextEvent.getEventType() != XMLStreamConstants.CHARACTERS)
+          logger.warn("ignoring event {}: '{}'", nextEvent.getEventType(), nextEvent.toString().replace("\n", "\\n"));
+      }
+
+      reader.nextEvent();
+      nextEvent = reader.peek();
+    }
+  }
+
+  private EClassifier parseEDataType(final XMLEventReader reader, Map<String, String> nameSpaces) throws XMLStreamException {
+    // TODO implement
+    return null;
+  }
+
+  private EClassifier parseEEnum(final XMLEventReader reader, Map<String, String> nameSpaces) throws XMLStreamException {
+    // TODO implement
+    return null;
+  }
+
+  private ETypeParameter parseETypeParameter(final XMLEventReader reader, Map<String, String> nameSpaces) throws XMLStreamException {
+    // TODO implement
+    return null;
+  }
+
+  private EStructuralFeature parseEStructuralFeature(final XMLEventReader reader, Map<String, String> nameSpaces) throws XMLStreamException {
+    StartElement startElement = reader.peek().asStartElement();
+
+    EStructuralFeature eStructuralFeature;
+
+    final String type = startElement.getAttributeByName(XSI_TYPE).getValue();
+    switch (type) {
+      case "ecore:EAttribute":
+        eStructuralFeature = parseEAttribute(reader, nameSpaces);
+        break;
+      case "ecore:EReference":
+        eStructuralFeature = parseEReference(reader, nameSpaces);
+        break;
+      default:
+        logger.error("Unknown subclass '{}' of EStructuralFeature found", type);
+        throw new XMIParseException("Unknown subclass '" + type + "' of EClassifier found");
+    }
+
+    return eStructuralFeature;
+  }
+
+  private EOperation parseEOperation(final XMLEventReader reader, Map<String, String> nameSpaces) throws XMLStreamException {
+    // TODO implement
+    return null;
+  }
+
+  private EGenericType parseEGenericSuperType(final XMLEventReader reader, Map<String, String> nameSpaces) throws XMLStreamException {
+    // TODO implement
+    return null;
+  }
+
+  private EAttribute parseEAttribute(final XMLEventReader reader, Map<String, String> nameSpaces) throws XMLStreamException {
+
+    EAttribute eAttribute = new EAttribute();
+
+    // get all the properties out of the element
+    StartElement startElement = reader.nextEvent().asStartElement();
+
+    nameSpaces = parseNameSpaces(startElement, nameSpaces);
+
+    for (Iterator attributeIterator = startElement.getAttributes(); attributeIterator.hasNext(); ) {
+      Attribute attribute = (Attribute) attributeIterator.next();
+
+      if (attribute.getName().equals(XSI_TYPE)) {
+        if (!attribute.getValue().equals("ecore:EAttribute")) {
+          throw new XMIParseException("Expected ecore:EAttribute but found " + attribute.getValue(), attribute.getLocation());
+        }
+      } else {
+        switch (attribute.getName().getLocalPart()) {
+          // from ENamedElement
+          case "name":
+            eAttribute.setName(attribute.getValue());
+            break;
+          // from ETypedElement
+          case "ordered":
+            eAttribute.setOrdered(Boolean.valueOf(attribute.getValue()));
+            break;
+          case "unique":
+            eAttribute.setUnique(Boolean.valueOf(attribute.getValue()));
+            break;
+          case "lowerBound":
+            eAttribute.setLowerBound(Integer.valueOf(attribute.getValue()));
+            break;
+          case "upperBound":
+            eAttribute.setUpperBound(Integer.valueOf(attribute.getValue()));
+            break;
+          case "eType":
+            eAttribute.setEType(EClassifier.createRefDirection(attribute.getValue()));
+            // from EStructuralFeature
+          case "changeable":
+            eAttribute.setChangeable(Boolean.valueOf(attribute.getValue()));
+            break;
+          case "volatile":
+            eAttribute.setVolatile(Boolean.valueOf(attribute.getValue()));
+            break;
+          case "transient":
+            eAttribute.setTransient(Boolean.valueOf(attribute.getValue()));
+            break;
+          case "defaultValueLiteral":
+            eAttribute.setdefaultValueLiteral(attribute.getValue());
+            break;
+          case "defaultValue":
+            logger.warn("ignoring attribute 'defaultValue' with value '{}'", attribute.getValue());
+            break;
+          case "unsettable":
+            eAttribute.setUnsettable(Boolean.valueOf(attribute.getValue()));
+            break;
+          case "derived":
+            eAttribute.setDerived(Boolean.valueOf(attribute.getValue()));
+            break;
+          case "eContainingClass":
+            logger.warn("ignoring parent relation 'eContainingClass' with value '{}'", attribute.getValue());
+            break;
+          // from EAttribute
+          case "iD":
+            eAttribute.setID(Boolean.valueOf(attribute.getValue()));
+            break;
+          default:
+            logger.warn("ignoring attribute {}:{}", attribute.getName().getPrefix(), attribute.getName().getLocalPart());
+        }
+      }
+
+    }
+
+    // parse the contained elements
+    XMLEvent nextEvent = reader.peek();
+    while (true) {
+      if (nextEvent.isEndElement() && nextEvent.asEndElement().getName().equals(startElement.getName())) {
+        return eAttribute;
+      } else {
+        // ignore all other events
+        if (nextEvent.getEventType() != XMLStreamConstants.CHARACTERS)
+          logger.warn("ignoring event {}: '{}'", nextEvent.getEventType(), nextEvent.toString().replace("\n", "\\n"));
+      }
+
+      reader.nextEvent();
+      nextEvent = reader.peek();
+    }
+  }
+
+  private EReference parseEReference(final XMLEventReader reader, Map<String, String> nameSpaces) throws XMLStreamException {
+
+    EReference eReference = new EReference();
+
+    // get all the properties out of the element
+    StartElement startElement = reader.nextEvent().asStartElement();
+
+    nameSpaces = parseNameSpaces(startElement, nameSpaces);
+
+    for (Iterator attributeIterator = startElement.getAttributes(); attributeIterator.hasNext(); ) {
+      Attribute attribute = (Attribute) attributeIterator.next();
+
+      if (attribute.getName().equals(XSI_TYPE)) {
+        if (!attribute.getValue().equals("ecore:EReference")) {
+          throw new XMIParseException("Expected ecore:EReference but found " + attribute.getValue(), attribute.getLocation());
+        }
+      } else {
+
+        switch (attribute.getName().getLocalPart()) {
+          // from ENamedElement
+          case "name":
+            eReference.setName(attribute.getValue());
+            break;
+          // from ETypedElement
+          case "ordered":
+            eReference.setOrdered(Boolean.valueOf(attribute.getValue()));
+            break;
+          case "unique":
+            eReference.setUnique(Boolean.valueOf(attribute.getValue()));
+            break;
+          case "lowerBound":
+            eReference.setLowerBound(Integer.valueOf(attribute.getValue()));
+            break;
+          case "upperBound":
+            eReference.setUpperBound(Integer.valueOf(attribute.getValue()));
+            break;
+          case "eType":
+            eReference.setEType(EClassifier.createRefDirection(attribute.getValue()));
+            // from EStructuralFeature
+          case "changeable":
+            eReference.setChangeable(Boolean.valueOf(attribute.getValue()));
+            break;
+          case "volatile":
+            eReference.setVolatile(Boolean.valueOf(attribute.getValue()));
+            break;
+          case "transient":
+            eReference.setTransient(Boolean.valueOf(attribute.getValue()));
+            break;
+          case "defaultValueLiteral":
+            eReference.setdefaultValueLiteral(attribute.getValue());
+            break;
+          case "unsettable":
+            eReference.setUnsettable(Boolean.valueOf(attribute.getValue()));
+            break;
+          case "derived":
+            eReference.setDerived(Boolean.valueOf(attribute.getValue()));
+            break;
+          case "eContainingClass":
+            logger.warn("ignoring parent relation 'eContainingClass' with value '{}'", attribute.getValue());
+            break;
+          // from EReference
+          case "containment":
+            eReference.setContainment(Boolean.valueOf(attribute.getValue()));
+            break;
+          case "resolveProxies":
+            eReference.setResolveProxies(Boolean.valueOf(attribute.getValue()));
+            break;
+          case "eOpposite":
+            eReference.setEOpposite(EReference.createRefDirection(attribute.getValue()));
+            break;
+          default:
+            logger.warn("ignoring attribute {}:{}", attribute.getName().getPrefix(), attribute.getName().getLocalPart());
+        }
+      }
+    }
+
+    // parse the contained elements
+    XMLEvent nextEvent = reader.peek();
+    while (true) {
+      if (nextEvent.isEndElement() && nextEvent.asEndElement().getName().equals(startElement.getName())) {
+        return eReference;
+      } else {
+        // ignore all other events
+        if (nextEvent.getEventType() != XMLStreamConstants.CHARACTERS)
+          logger.warn("ignoring event {}: '{}'", nextEvent.getEventType(), nextEvent.toString().replace("\n", "\\n"));
+      }
+
+      reader.nextEvent();
+      nextEvent = reader.peek();
+    }
+  }
+}
diff --git a/src/main/java/de/tudresden/inf/st/e2j/parser/XMIParseException.java b/src/main/java/de/tudresden/inf/st/e2j/parser/XMIParseException.java
new file mode 100644
index 0000000000000000000000000000000000000000..14e66f9ddcdf2e303eefaa2ecd1303b00a83a03a
--- /dev/null
+++ b/src/main/java/de/tudresden/inf/st/e2j/parser/XMIParseException.java
@@ -0,0 +1,29 @@
+package de.tudresden.inf.st.e2j.parser;
+
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLStreamException;
+
+public class XMIParseException extends XMLStreamException {
+  public XMIParseException() {
+  }
+
+  public XMIParseException(String msg) {
+    super(msg);
+  }
+
+  public XMIParseException(Throwable th) {
+    super(th);
+  }
+
+  public XMIParseException(String msg, Throwable th) {
+    super(msg, th);
+  }
+
+  public XMIParseException(String msg, Location location, Throwable th) {
+    super(msg, location, th);
+  }
+
+  public XMIParseException(String msg, Location location) {
+    super(msg, location);
+  }
+}
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
index 37f93cadef70ad8a48a74027a71e5a9d09910142..c243823993c50f06c43c520f94e0720d02eb6c2e 100644
--- a/src/main/resources/log4j2.xml
+++ b/src/main/resources/log4j2.xml
@@ -2,7 +2,7 @@
 <Configuration>
     <Appenders>
         <Console name="Console">
-            <PatternLayout pattern="%highlight{%d{HH:mm:ss.SSS} %-5level} %c{1.} - %msg%n"/>
+            <PatternLayout pattern="%highlight{%d{HH:mm:ss.SSS} %-5level} %c{1.}:%M() - %msg%n"/>
         </Console>
         <RollingFile name="RollingFile" fileName="logs/jastadd-ttc19.log"
                     filePattern="logs/jastadd-ttc19-%i.log">
diff --git a/src/test/java/de/tudresden/inf/st/e2j/parser/ParserTest.java b/src/test/java/de/tudresden/inf/st/e2j/parser/ParserTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7c8b0244919bc62b1913efb429c6eab521d28723
--- /dev/null
+++ b/src/test/java/de/tudresden/inf/st/e2j/parser/ParserTest.java
@@ -0,0 +1,42 @@
+package de.tudresden.inf.st.e2j.parser;
+
+import de.tudresden.inf.st.e2j.jastadd.model.EObject;
+import de.tudresden.inf.st.e2j.jastadd.model.EPackage;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+class ParserTest {
+
+  @Test
+  void parsePackage() {
+
+    EObject ePackage = null;
+
+    final String fileName = "/ecore/bigraph.ecore";
+
+    EcoreParser parser = new EcoreParser();
+
+    try (InputStream stream = this.getClass().getResourceAsStream(fileName)) {
+      Assertions.assertNotNull(stream, "unable to load resource '" + fileName + "'");
+      ePackage = parser.parse(stream);
+    } catch (IOException | XMIParseException e) {
+      Assertions.fail(e);
+    }
+
+    Assertions.assertNotNull(ePackage);
+
+    Assertions.assertTrue(ePackage instanceof EPackage);
+
+    EPackage p = (EPackage) ePackage;
+
+    StringBuilder b = new StringBuilder();
+
+    p.writeXMI(b);
+
+    System.out.println(b.toString());
+  }
+
+}
diff --git a/src/test/resources/ecore/bigraph.ecore b/src/test/resources/ecore/bigraph.ecore
new file mode 100644
index 0000000000000000000000000000000000000000..db72fd127a191003ed74e6712a973bcf759409dd
--- /dev/null
+++ b/src/test/resources/ecore/bigraph.ecore
@@ -0,0 +1,47 @@
+<?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="bigraphBaseModel"
+                nsURI="http://de.tudresden.inf.st.bigraphs.models"
+                nsPrefix="bigraphBaseModel">
+    <eClassifiers xsi:type="ecore:EClass" name="BPlace" abstract="true">
+        <eStructuralFeatures xsi:type="ecore:EReference" name="bChild" upperBound="-1"
+                             eType="#//BPlace" containment="true" eOpposite="#//BPlace/bPrnt"/>
+        <eStructuralFeatures xsi:type="ecore:EReference" name="bPrnt" eType="#//BPlace"
+                             eOpposite="#//BPlace/bChild"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="BRoot" eSuperTypes="#//BPlace">
+        <eStructuralFeatures xsi:type="ecore:EAttribute" name="index"
+                             eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="BNode" eSuperTypes="#//BPlace #//NameableType">
+        <eStructuralFeatures xsi:type="ecore:EReference" name="bPorts" upperBound="-1"
+                             eType="#//BPort" containment="true" eOpposite="#//BPort/bNode"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="BSite" eSuperTypes="#//BPlace">
+        <eStructuralFeatures xsi:type="ecore:EAttribute" name="index"
+                             eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="BPoint" abstract="true">
+        <eStructuralFeatures xsi:type="ecore:EReference" name="bLink" lowerBound="1" eType="#//BLink"
+                             eOpposite="#//BLink/bPoints"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="BLink" abstract="true" eSuperTypes="#//NameableType">
+        <eStructuralFeatures xsi:type="ecore:EReference" name="bPoints" lowerBound="1"
+                             upperBound="-1" eType="#//BPoint" eOpposite="#//BPoint/bLink"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="BPort" eSuperTypes="#//BPoint">
+        <eStructuralFeatures xsi:type="ecore:EAttribute" name="index"
+                             eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
+        <eStructuralFeatures xsi:type="ecore:EReference" name="bNode" lowerBound="1" eType="#//BNode"
+                             eOpposite="#//BNode/bPorts"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="BInnerName" eSuperTypes="#//BPoint #//NameableType"/>
+    <eClassifiers xsi:type="ecore:EClass" name="BEdge" eSuperTypes="#//BLink"/>
+    <eClassifiers xsi:type="ecore:EClass" name="BOuterName" eSuperTypes="#//BLink"/>
+    <eClassifiers xsi:type="ecore:EClass" name="NameableType" abstract="true" interface="true">
+        <eStructuralFeatures xsi:type="ecore:EAttribute" name="name"
+                             eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
+                             iD="true"/>
+    </eClassifiers>
+</ecore:EPackage>
diff --git a/src/test/resources/ecore/package.ecore b/src/test/resources/ecore/package.ecore
new file mode 100644
index 0000000000000000000000000000000000000000..fe80565bfd5aa6d17796f87fde98b3f126961493
--- /dev/null
+++ b/src/test/resources/ecore/package.ecore
@@ -0,0 +1,7 @@
+<?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="bigraphBaseModel"
+                nsURI="http://de.tudresden.inf.st.bigraphs.models"
+                nsPrefix="bigraphBaseModel">
+</ecore:EPackage>