diff --git a/src/main/jastadd/XMI/XMIPathConstruction.jrag b/src/main/jastadd/XMI/XMIPathConstruction.jrag
index a2bbe0b94eab4bcd5fb53a8dad49dfab047292bf..d2189bbd7d50cc40b8b94a92ae0b5ff88a6186d0 100644
--- a/src/main/jastadd/XMI/XMIPathConstruction.jrag
+++ b/src/main/jastadd/XMI/XMIPathConstruction.jrag
@@ -3,24 +3,79 @@ aspect XMIPathConstruction {
 
   syn String EModelElement.xmiReference() = xmiPath() + localName();
 
+  eq EClass.xmiReference() {
+    if (getParent() == null) {
+      if (this == eObject())
+        return "ecore:EClass http://www.eclipse.org/emf/2002/Ecore#//EObject";
+      else
+        throw new RuntimeException("Unable to create reference to EClass " + getName());
+
+    } else {
+      return super.xmiReference();
+    }
+  }
+
   eq EDataType.xmiReference() {
     if (getParent() == null) {
-      switch (getName()) {
-        case "EInt":
-          return "ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt";
-        case "EString":
-          return "ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString";
-        case "EBoolean":
-          return "ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean";
-        case "EJavaObject":
-          return "ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EJavaObject";
-        case "EEnumerator":
-          return "ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EEnumerator";
-        case "EResource":
-          return "ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EResource";
-        default:
-          throw new RuntimeException("Unable to create reference to EDataType " + getName());
-      }
+      if (this == eInt())
+        return "ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt";
+      else if (this == eString())
+        return "ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString";
+      else if (this == eBoolean())
+        return "ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean";
+      else if (this == eJavaObject())
+        return "ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EJavaObject";
+      else if (this == eEnumerator())
+        return "ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EEnumerator";
+      else if (this == eResource())
+        return "ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EResource";
+      else if (this == xmlDateTime())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//DateTime";
+      else if (this == xmlBoolean())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//Boolean";
+      else if (this == xmlByte())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//Byte";
+      else if (this == xmlNormalizedString())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//NormalizedString";
+      else if (this == xmlString())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//String";
+      else if (this == xmlInteger())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//Integer";
+      else if (this == xmlDate())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//Date";
+      else if (this == xmlDecimal())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//Decimal";
+      else if (this == xmlDuration())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//Duration";
+      else if (this == xmlLanguage())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//Language";
+      else if (this == xmlInt())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//Int";
+      else if (this == xmlLong())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//Long";
+      else if (this == xmlAnyURI())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//AnyURI";
+      else if (this == xmlBase64Binary())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//Base64Binary";
+      else if (this == xmlNegativeInteger())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//NegativeInteger";
+      else if (this == xmlNonNegativeInteger())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//NonNegativeInteger";
+      else if (this == xmlNonPositiveInteger())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//NonPositiveInteger";
+      else if (this == xmlToken())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//Token";
+      else if (this == xmlPositiveInteger())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//PositiveInteger";
+      else if (this == xmlShort())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//Short";
+      else if (this == xmlTime())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//Time";
+      else if (this == xmlUnsignedByte())
+        return "ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//UnsignedByte";
+      else
+        throw new RuntimeException("Unable to create reference to EDataType " + getName());
+
     } else {
       return super.xmiReference();
     }
@@ -31,7 +86,20 @@ aspect XMIPathConstruction {
       if (getParent() != null) {
         return xmiPath() + localName();
       } else {
-        return "#/";
+        if (this instanceof EPackage) {
+          EPackage ePackage = ((EPackage)this);
+          int numPackages = ePackage.getPackageList().size();
+          if (numPackages > 1) {
+            for (int index = 0; index < numPackages; index++) {
+              if (ePackage.getPackageList().get(index) == this) return "/" + index;
+            }
+            throw new RuntimeException("Unable to create reference to EPackage, because it is not in the list of packages.");
+          } else {
+            return "#/";
+          }
+        } else {
+          return "#/";
+        }
       }
     }
 
diff --git a/src/main/jastadd/XMI/XMIPathResolution.jrag b/src/main/jastadd/XMI/XMIPathResolution.jrag
index e72245b0b1d0abac93f2ff612bb3b826ea04da21..b331f19d05ece3eaabf0017d2114649a7642c9e2 100644
--- a/src/main/jastadd/XMI/XMIPathResolution.jrag
+++ b/src/main/jastadd/XMI/XMIPathResolution.jrag
@@ -22,6 +22,15 @@ aspect XMIPathResolution {
     return (EClassifier) resolve(id);
   }
 
+  private static EClass EClass.eObject;
+  public static final EClass EClass.eObject() {
+    if (eObject == null) {
+      eObject = new EClass();
+      eObject.setName("EObject");
+    }
+    return eObject;
+  }
+
   private static EDataType EDataType.eInt;
   public static final EDataType EDataType.eInt() {
     if (eInt == null) {
@@ -82,11 +91,239 @@ aspect XMIPathResolution {
     return eResource;
   }
 
+  private static EDataType EDataType.xmlDateTime;
+  public static final EDataType EDataType.xmlDateTime() {
+    if (xmlDateTime == null) {
+      xmlDateTime = new EDataType();
+      xmlDateTime.setInstanceClassName("javax.xml.datatype.XMLGregorianCalendar");
+      xmlDateTime.setName("DateTime");
+    }
+    return xmlDateTime;
+  }
+
+  private static EDataType EDataType.xmlBoolean;
+  public static final EDataType EDataType.xmlBoolean() {
+    if (xmlBoolean == null) {
+      xmlBoolean = new EDataType();
+      xmlBoolean.setInstanceClassName("boolean");
+      xmlBoolean.setName("Boolean");
+    }
+    return xmlBoolean;
+  }
+
+  private static EDataType EDataType.xmlByte;
+  public static final EDataType EDataType.xmlByte() {
+    if (xmlByte == null) {
+      xmlByte = new EDataType();
+      xmlByte.setInstanceClassName("byte");
+      xmlByte.setName("Byte");
+    }
+    return xmlBoolean;
+  }
+
+  private static EDataType EDataType.xmlNormalizedString;
+  public static final EDataType EDataType.xmlNormalizedString() {
+    if (xmlNormalizedString == null) {
+      xmlNormalizedString = new EDataType();
+      xmlNormalizedString.setInstanceClassName("java.lang.String");
+      xmlNormalizedString.setName("NormalizedString");
+    }
+    return xmlNormalizedString;
+  }
+
+  private static EDataType EDataType.xmlString;
+  public static final EDataType EDataType.xmlString() {
+    if (xmlString == null) {
+      xmlString = new EDataType();
+      xmlString.setInstanceClassName("java.lang.String");
+      xmlString.setName("String");
+    }
+    return xmlString;
+  }
+
+  private static EDataType EDataType.xmlInteger;
+  public static final EDataType EDataType.xmlInteger() {
+    if (xmlInteger == null) {
+      xmlInteger = new EDataType();
+      xmlInteger.setInstanceClassName("java.lang.Integer");
+      xmlInteger.setName("Integer");
+    }
+    return xmlInteger;
+  }
+
+  private static EDataType EDataType.xmlDate;
+  public static final EDataType EDataType.xmlDate() {
+    if (xmlDate == null) {
+      xmlDate = new EDataType();
+      xmlDate.setInstanceClassName("javax.xml.datatype.XMLGregorianCalendar");
+      xmlDate.setName("Date");
+    }
+    return xmlDate;
+  }
+
+  private static EDataType EDataType.xmlDecimal;
+  public static final EDataType EDataType.xmlDecimal() {
+    if (xmlDecimal == null) {
+      xmlDecimal = new EDataType();
+      xmlDecimal.setInstanceClassName("java.math.BigDecimal");
+      xmlDecimal.setName("Decimal");
+    }
+    return xmlDecimal;
+  }
+
+  private static EDataType EDataType.xmlDuration;
+  public static final EDataType EDataType.xmlDuration() {
+    if (xmlDuration == null) {
+      xmlDuration = new EDataType();
+      xmlDuration.setInstanceClassName("javax.xml.datatype.Duration");
+      xmlDuration.setName("Duration");
+    }
+    return xmlDuration;
+  }
+
+  private static EDataType EDataType.xmlLanguage;
+  public static final EDataType EDataType.xmlLanguage() {
+    if (xmlLanguage == null) {
+      xmlLanguage = new EDataType();
+      xmlLanguage.setInstanceClassName("java.lang.String");
+      xmlLanguage.setName("Language");
+    }
+    return xmlLanguage;
+  }
+
+  private static EDataType EDataType.xmlInt;
+  public static final EDataType EDataType.xmlInt() {
+    if (xmlInt == null) {
+      xmlInt = new EDataType();
+      xmlInt.setInstanceClassName("int");
+      xmlInt.setName("Int");
+    }
+    return xmlInt;
+  }
+
+  private static EDataType EDataType.xmlLong;
+  public static final EDataType EDataType.xmlLong() {
+    if (xmlLong == null) {
+      xmlLong = new EDataType();
+      xmlLong.setInstanceClassName("long");
+      xmlLong.setName("Long");
+    }
+    return xmlLong;
+  }
+
+  private static EDataType EDataType.xmlAnyURI;
+  public static final EDataType EDataType.xmlAnyURI() {
+    if (xmlAnyURI == null) {
+      xmlAnyURI = new EDataType();
+      xmlAnyURI.setInstanceClassName("java.lang.String");
+      xmlAnyURI.setName("AnyURI");
+    }
+    return xmlAnyURI;
+  }
+
+  private static EDataType EDataType.xmlBase64Binary;
+  public static final EDataType EDataType.xmlBase64Binary() {
+    if (xmlBase64Binary == null) {
+      xmlBase64Binary = new EDataType();
+      xmlBase64Binary.setInstanceClassName("byte[]");
+      xmlBase64Binary.setName("Base64Binary");
+    }
+    return xmlBase64Binary;
+  }
+
+  private static EDataType EDataType.xmlNegativeInteger;
+  public static final EDataType EDataType.xmlNegativeInteger() {
+    if (xmlNegativeInteger == null) {
+      xmlNegativeInteger = new EDataType();
+      xmlNegativeInteger.setInstanceClassName("java.math.BigInteger");
+      xmlNegativeInteger.setName("NegativeInteger");
+    }
+    return xmlNegativeInteger;
+  }
+
+  private static EDataType EDataType.xmlNonNegativeInteger;
+  public static final EDataType EDataType.xmlNonNegativeInteger() {
+    if (xmlNonNegativeInteger == null) {
+      xmlNonNegativeInteger = new EDataType();
+      xmlNonNegativeInteger.setInstanceClassName("java.math.BigInteger");
+      xmlNonNegativeInteger.setName("NonNegativeInteger");
+    }
+    return xmlNonNegativeInteger;
+  }
+
+  private static EDataType EDataType.xmlPositiveInteger;
+  public static final EDataType EDataType.xmlPositiveInteger() {
+    if (xmlPositiveInteger == null) {
+      xmlPositiveInteger = new EDataType();
+      xmlPositiveInteger.setInstanceClassName("java.math.BigInteger");
+      xmlPositiveInteger.setName("PositiveInteger");
+    }
+    return xmlPositiveInteger;
+  }
+
+  private static EDataType EDataType.xmlNonPositiveInteger;
+  public static final EDataType EDataType.xmlNonPositiveInteger() {
+    if (xmlNonPositiveInteger == null) {
+      xmlNonPositiveInteger = new EDataType();
+      xmlNonPositiveInteger.setInstanceClassName("java.math.BigInteger");
+      xmlNonPositiveInteger.setName("NonPositiveInteger");
+    }
+    return xmlNonPositiveInteger;
+  }
+
+  private static EDataType EDataType.xmlToken;
+  public static final EDataType EDataType.xmlToken() {
+    if (xmlToken == null) {
+      xmlToken = new EDataType();
+      xmlToken.setInstanceClassName("java.lang.String");
+      xmlToken.setName("Token");
+    }
+    return xmlToken;
+  }
+
+  private static EDataType EDataType.xmlShort;
+  public static final EDataType EDataType.xmlShort() {
+    if (xmlShort == null) {
+      xmlShort = new EDataType();
+      xmlShort.setInstanceClassName("short");
+      xmlShort.setName("Short");
+    }
+    return xmlShort;
+  }
+
+  private static EDataType EDataType.xmlTime;
+  public static final EDataType EDataType.xmlTime() {
+    if (xmlTime == null) {
+      xmlTime = new EDataType();
+      xmlTime.setInstanceClassName("javax.xml.datatype.XMLGregorianCalendar");
+      xmlTime.setName("Time");
+    }
+    return xmlTime;
+  }
+
+  private static EDataType EDataType.xmlUnsignedByte;
+  public static final EDataType EDataType.xmlUnsignedByte() {
+    if (xmlUnsignedByte == null) {
+      xmlUnsignedByte = new EDataType();
+      xmlUnsignedByte.setInstanceClassName("short");
+      xmlUnsignedByte.setName("UnsignedByte");
+    }
+    return xmlUnsignedByte;
+  }
+
   syn ASTNode ASTNode.resolve(String uriString) {
 
     // built-in data types
-    if (uriString.startsWith("ecore:EDataType ")) {
+    if (uriString.startsWith("ecore:EClass ")) {
+      switch (uriString.substring(13)) {
+        case "http://www.eclipse.org/emf/2002/Ecore#//EObject":
+          return EClass.eObject();
+        default:
+          throw new RuntimeException("Unable to resolve built-in class '" + uriString + "'");
+      }
+    } else if (uriString.startsWith("ecore:EDataType ")) {
       switch (uriString.substring(16)) {
+        case "http://www.eclipse.org/emf/2002/Ecore#//EObject":
         case "http://www.eclipse.org/emf/2002/Ecore#//EInt":
           return EDataType.eInt();
         case "http://www.eclipse.org/emf/2002/Ecore#//EString":
@@ -99,6 +336,48 @@ aspect XMIPathResolution {
           return EDataType.eEnumerator();
         case "http://www.eclipse.org/emf/2002/Ecore#//EResource":
           return EDataType.eResource();
+        case "http://www.eclipse.org/emf/2003/XMLType#//DateTime":
+          return EDataType.xmlDateTime();
+        case "http://www.eclipse.org/emf/2003/XMLType#//Boolean":
+          return EDataType.xmlBoolean();
+        case "http://www.eclipse.org/emf/2003/XMLType#//Byte":
+          return EDataType.xmlByte();
+        case "http://www.eclipse.org/emf/2003/XMLType#//Integer":
+          return EDataType.xmlInteger();
+        case "http://www.eclipse.org/emf/2003/XMLType#//Date":
+          return EDataType.xmlDate();
+        case "http://www.eclipse.org/emf/2003/XMLType#//Decimal":
+          return EDataType.xmlDecimal();
+        case "http://www.eclipse.org/emf/2003/XMLType#//Duration":
+          return EDataType.xmlDuration();
+        case "http://www.eclipse.org/emf/2003/XMLType#//Language":
+          return EDataType.xmlLanguage();
+        case "http://www.eclipse.org/emf/2003/XMLType#//Int":
+          return EDataType.xmlInt();
+        case "http://www.eclipse.org/emf/2003/XMLType#//Long":
+          return EDataType.xmlLong();
+        case "http://www.eclipse.org/emf/2003/XMLType#//AnyURI":
+          return EDataType.xmlAnyURI();
+        case "http://www.eclipse.org/emf/2003/XMLType#//Base64Binary":
+          return EDataType.xmlBase64Binary();
+        case "http://www.eclipse.org/emf/2003/XMLType#//NegativeInteger":
+          return EDataType.xmlNegativeInteger();
+        case "http://www.eclipse.org/emf/2003/XMLType#//NonNegativeInteger":
+          return EDataType.xmlNonNegativeInteger();
+        case "http://www.eclipse.org/emf/2003/XMLType#//NonPositiveInteger":
+          return EDataType.xmlNonPositiveInteger();
+        case "http://www.eclipse.org/emf/2003/XMLType#//Token":
+          return EDataType.xmlToken();
+        case "http://www.eclipse.org/emf/2003/XMLType#//PositiveInteger":
+          return EDataType.xmlPositiveInteger();
+        case "http://www.eclipse.org/emf/2003/XMLType#//Short":
+          return EDataType.xmlShort();
+        case "http://www.eclipse.org/emf/2003/XMLType#//UnsignedByte":
+          return EDataType.xmlUnsignedByte();
+        case "http://www.eclipse.org/emf/2003/XMLType#//NormalizedString":
+          return EDataType.xmlNormalizedString();
+        case "http://www.eclipse.org/emf/2003/XMLType#//String":
+          return EDataType.xmlString();
         default:
           throw new RuntimeException("Unable to resolve built-in data type '" + uriString + "'");
       }
@@ -158,7 +437,19 @@ aspect XMIPathResolution {
   syn ASTNode ASTNode.resolvePathRootFragment(String fragment) {
     // This method is only relevant if there are multiple roots, and in this case, in general, it is not possible to
     // select the right one (because we cannot navigate to them)
-    return root();
+
+    ASTNode root = root();
+
+    if (root instanceof EPackage) {
+      EPackage ownPackage = (EPackage) root;
+      if (ownPackage.getPackageList().size() == 1) {
+        return root;
+      } else {
+        return ownPackage.getPackageList().get(Integer.valueOf(fragment));
+      }
+    } else {
+      return root;
+    }
   }
 
   syn ASTNode ASTNode.resolvePathFragment(String fragment) {
@@ -257,7 +548,7 @@ aspect XMIPathResolution {
       }
     }
 
-    throw new RuntimeException("Unable to find number '" + index + "'child with name '" + name + "'");
+    throw new RuntimeException("Unable to find child number '" + index + "' with name '" + name + "'");
   }
 
 //  public static String getID(EObject eObject) {
diff --git a/src/main/jastadd/XMI/XMIWriter.jadd b/src/main/jastadd/XMI/XMIWriter.jadd
index 62c69554cfbe23d671c482b6dd7bc6db0422d1bd..96c54a409b35488b241f727e47adae89a04b4747 100644
--- a/src/main/jastadd/XMI/XMIWriter.jadd
+++ b/src/main/jastadd/XMI/XMIWriter.jadd
@@ -7,20 +7,38 @@ aspect XMIWriter {
   }
 
   public void EPackage.writeXMI(StringBuilder b) {
-    b.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
-    this.writeXMI(b, null, 0);
+    writeXMI(b, "UTF-8");
   }
 
-  void ASTNode.startXMIElement(StringBuilder b, String type, String context) {
+  public void EPackage.writeXMI(StringBuilder b, String encoding) {
+    b.append("<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>\n");
+    if (getPackageList().size() > 1) {
+      b.append("<xmi:XMI 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\">\n");
+      for (EPackage p : getPackageList()) {
+        p.writeXMI(b, null, 1, false, false);
+      }
+      b.append("</xmi:XMI>\n");
+    } else {
+      this.writeXMI(b, null, 0, true, false);
+    }
+  }
+
+  void ASTNode.startXMIElement(StringBuilder b, String type, String context, boolean topLevel, boolean requiresType) {
     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\"");
+      b.append(type);
+      if (topLevel) {
+        // we have a top-level element that is not contained in anything
+        b.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);
-      if (!"".equals(type)) {
+      if (requiresType) {
         // TODO whether to print the type can be determined by static analysis!
         b.append(" xsi:type=\"").append(type).append("\"");
       }
@@ -31,17 +49,22 @@ aspect XMIWriter {
     b.append((context == null) ? type : context);
   }
 
-  void EPackage.writeXMI(StringBuilder b, String context, int indentationLevel) {
+  void EPackage.writeXMI(StringBuilder b, String context, int indentationLevel, boolean topLevel, boolean requiresType) {
     // opening tag
     b.append(indentString(indentationLevel)).append("<");
-    startXMIElement(b, "ecore:EPackage", context);
+    startXMIElement(b, "ecore:EPackage", context, topLevel, requiresType);
 
     // attributes
     // from ENamedElement
     b.append(" name=\"").append(getName()).append("\"");
     // from EPackage
-    b.append(" nsURI=\"").append(getNsURI()).append("\"")
-      .append(" nsPrefix=\"").append(getNsPrefix()).append("\"");
+    if (getNsURI() != null && !getNsURI().equals("")) {
+      b.append(" nsURI=\"").append(getNsURI()).append("\"");
+    }
+    if (getNsPrefix() != null && !getNsPrefix().equals("")) {
+      b.append(" nsPrefix=\"").append(getNsPrefix()).append("\"");
+    }
+
     if (numContainedChildren() == 0) {
       b.append("/>\n");
       return;
@@ -51,14 +74,14 @@ aspect XMIWriter {
     // child nodes
     // from EModelElement
     for (EAnnotation eAnnotation : getEAnnotationList()) {
-      eAnnotation.writeXMI(b, "eAnnotations", indentationLevel + 1);
+      eAnnotation.writeXMI(b, "eAnnotations", indentationLevel + 1, false, false);
     }
     // from EPackage
     for (EClassifier eClassifier : getEClassifierList()) {
-      eClassifier.writeXMI(b, "eClassifiers", indentationLevel + 1);
+      eClassifier.writeXMI(b, "eClassifiers", indentationLevel + 1, false, true);
     }
     for (EPackage eSubpackage : getESubPackageList()) {
-      eSubpackage.writeXMI(b, "eSubpackages", indentationLevel + 1);
+      eSubpackage.writeXMI(b, "eSubpackages", indentationLevel + 1, false, false);
     }
 
     // closing tag
@@ -67,11 +90,11 @@ aspect XMIWriter {
     b.append(">\n");
   }
 
-  abstract void EClassifier.writeXMI(StringBuilder b, String context, int indentationLevel);
+  abstract void EClassifier.writeXMI(StringBuilder b, String context, int indentationLevel, boolean topLevel, boolean requiresType);
 
-  void EClass.writeXMI(StringBuilder b, String context, int indentationLevel) {
+  void EClass.writeXMI(StringBuilder b, String context, int indentationLevel, boolean topLevel, boolean requiresType) {
     b.append(indentString(indentationLevel)).append("<");
-    startXMIElement(b, "ecore:EClass", context);
+    startXMIElement(b, "ecore:EClass", context, topLevel, requiresType);
     // attributes
     // from ENamedElement
     b.append(" name=\"").append(getName()).append("\"");
@@ -108,21 +131,21 @@ aspect XMIWriter {
     // child nodes
     // from EModelElement
     for (EAnnotation eAnnotation : getEAnnotationList()) {
-      eAnnotation.writeXMI(b, "eAnnotations", indentationLevel + 1);
+      eAnnotation.writeXMI(b, "eAnnotations", indentationLevel + 1, false, false);
     }
     // from EClassifier
     for (ETypeParameter eTypeParameter : getETypeParameterList()) {
-      eTypeParameter.writeXMI(b, "eTypeParameters", indentationLevel + 1);
+      eTypeParameter.writeXMI(b, "eTypeParameters", indentationLevel + 1, false, false);
     }
     // from EClass
     for (EOperation eOperation : getEOperationList()) {
-      eOperation.writeXMI(b, "eOperations", indentationLevel + 1);
+      eOperation.writeXMI(b, "eOperations", indentationLevel + 1, false, false);
     }
     for (EStructuralFeature eStructuralFeature : getEStructuralFeatureList()) {
-      eStructuralFeature.writeXMI(b, "eStructuralFeatures", indentationLevel + 1);
+      eStructuralFeature.writeXMI(b, "eStructuralFeatures", indentationLevel + 1, false, true);
     }
     for (EGenericType eGenericSuperType : getEGenericSuperTypeList()) {
-      eGenericSuperType.writeXMI(b, "eGenericSuperTypes", indentationLevel + 1);
+      eGenericSuperType.writeXMI(b, "eGenericSuperTypes", indentationLevel + 1, false, false);
     }
 
     // closing tag
@@ -131,9 +154,9 @@ aspect XMIWriter {
     b.append(">\n");
   }
 
-  void EDataType.writeXMI(StringBuilder b, String context, int indentationLevel) {
+  void EDataType.writeXMI(StringBuilder b, String context, int indentationLevel, boolean topLevel, boolean requiresType) {
     b.append(indentString(indentationLevel)).append("<");
-    startXMIElement(b, "ecore:EDataType", context);
+    startXMIElement(b, "ecore:EDataType", context, topLevel, requiresType);
     // attributes
     b.append(" name=\"").append(getName()).append("\"");
     // from EClassifier
@@ -154,11 +177,11 @@ aspect XMIWriter {
     // child nodes
     // from EModelElement
     for (EAnnotation eAnnotation : getEAnnotationList()) {
-      eAnnotation.writeXMI(b, "eAnnotations", indentationLevel + 1);
+      eAnnotation.writeXMI(b, "eAnnotations", indentationLevel + 1, false, false);
     }
     // from EClassifier
     for (ETypeParameter eTypeParameter : getETypeParameterList()) {
-      eTypeParameter.writeXMI(b, "eTypeParameters", indentationLevel + 1);
+      eTypeParameter.writeXMI(b, "eTypeParameters", indentationLevel + 1, false, false);
     }
 
     // closing tag
@@ -167,9 +190,78 @@ aspect XMIWriter {
     b.append(">\n");
   }
 
-  void EGenericType.writeXMI(StringBuilder b, String context, int indentationLevel) {
+  void EEnum.writeXMI(StringBuilder b, String context, int indentationLevel, boolean topLevel, boolean requiresType) {
+    b.append(indentString(indentationLevel)).append("<");
+    startXMIElement(b, "ecore:EEnum", context, topLevel, requiresType);
+    // attributes
+    b.append(" name=\"").append(getName()).append("\"");
+    // from EClassifier
+    if (getInstanceClassName() != "") {
+      b.append(" instanceClassName=\"").append(getInstanceClassName()).append("\"");
+    }
+    // from EDataType
+    if (getSerializable() == false) {
+      b.append(" serializable=\"false\"");
+    }
+
+    if (numContainedChildren() == 0) {
+      b.append("/>\n");
+      return;
+    }
+    b.append(">\n");
+
+    // child nodes
+    // from EModelElement
+    for (EAnnotation eAnnotation : getEAnnotationList()) {
+      eAnnotation.writeXMI(b, "eAnnotations", indentationLevel + 1, false, false);
+    }
+    // from EClassifier
+    for (ETypeParameter eTypeParameter : getETypeParameterList()) {
+      eTypeParameter.writeXMI(b, "eTypeParameters", indentationLevel + 1, false, false);
+    }
+    // from EEnum
+    for (EEnumLiteral eLiteral : getELiteralList()) {
+      eLiteral.writeXMI(b, "eLiterals", indentationLevel + 1, false, false);
+    }
+
+    // closing tag
+    b.append(indentString(indentationLevel)).append("</");
+    endXMIElement(b, "ecore:EEnum", context);
+    b.append(">\n");
+  }
+
+  void EEnumLiteral.writeXMI(StringBuilder b, String context, int indentationLevel, boolean topLevel, boolean requiresType) {
+    b.append(indentString(indentationLevel)).append("<");
+    startXMIElement(b, "", context, topLevel, requiresType);
+    // attributes
+    // from ENamedElement
+    if (getName() != null && !getName().equals("")) {
+      b.append(" name=\"").append(getName()).append("\"");
+    }
+    // from ENamedElement
+    b.append(" value=\"").append(getValue()).append("\"");
+
+    if (numContainedChildren() == 0) {
+      b.append("/>\n");
+      return;
+    }
+    b.append(">\n");
+
+    // child nodes
+    // from EModelElement
+    for (EAnnotation eAnnotation : getEAnnotationList()) {
+      eAnnotation.writeXMI(b, "eAnnotations", indentationLevel + 1, false, false);
+    }
+
+    // closing tag
+    b.append(indentString(indentationLevel)).append("</");
+    endXMIElement(b, "", context);
+    b.append(">\n");
+  }
+
+  void EGenericType.writeXMI(StringBuilder b, String context, int indentationLevel, boolean topLevel, boolean requiresType) {
     b.append(indentString(indentationLevel)).append("<");
-    startXMIElement(b, "", context);
+    startXMIElement(b, "", context, topLevel, requiresType);
     // attributes
     if (hasETypeParameter()) {
       b.append(" eTypeParameter=\"").append(getETypeParameter().xmiReference()).append("\"");
@@ -185,13 +277,13 @@ aspect XMIWriter {
     // child nodes
     // from EGenericType
     if (hasEUpperBound()) {
-      getEUpperBound().writeXMI(b, "eUpperBound", indentationLevel + 1);
+      getEUpperBound().writeXMI(b, "eUpperBound", indentationLevel + 1, false, false);
     }
     if (hasELowerBound()) {
-      getELowerBound().writeXMI(b, "eLowerBound", indentationLevel + 1);
+      getELowerBound().writeXMI(b, "eLowerBound", indentationLevel + 1, false, false);
     }
     for (EGenericType eTypeArgument : getETypeArgumentList()) {
-      eTypeArgument.writeXMI(b, "eTypeArguments", indentationLevel + 1);
+      eTypeArgument.writeXMI(b, "eTypeArguments", indentationLevel + 1, false, false);
     }
 
     // closing tag
@@ -200,9 +292,9 @@ aspect XMIWriter {
     b.append(">\n");
   }
 
-  void EOperation.writeXMI(StringBuilder b, String context, int indentationLevel) {
+  void EOperation.writeXMI(StringBuilder b, String context, int indentationLevel, boolean topLevel, boolean requiresType) {
     b.append(indentString(indentationLevel)).append("<");
-    startXMIElement(b, "", context);
+    startXMIElement(b, "", context, topLevel, requiresType);
     // attributes
     // from ENamedElement
     b.append(" name=\"").append(getName()).append("\"");
@@ -234,21 +326,21 @@ aspect XMIWriter {
     // child nodes
     // from EModelElement
     for (EAnnotation eAnnotation : getEAnnotationList()) {
-      eAnnotation.writeXMI(b, "eAnnotations", indentationLevel + 1);
+      eAnnotation.writeXMI(b, "eAnnotations", indentationLevel + 1, false, false);
     }
     // from ETypedElement
     if (hasEGenericType()) {
-      getEGenericType().writeXMI(b, "eGenericType", indentationLevel + 1);
+      getEGenericType().writeXMI(b, "eGenericType", indentationLevel + 1, false, false);
     }
     // from EOperation
     for (EGenericType eGenericException : getEGenericExceptionList()) {
-      eGenericException.writeXMI(b, "eGenericExceptions", indentationLevel + 1);
+      eGenericException.writeXMI(b, "eGenericExceptions", indentationLevel + 1, false, false);
     }
     for (ETypeParameter eTypeParameter : getETypeParameterList()) {
-      eTypeParameter.writeXMI(b, "eTypeParameters", indentationLevel + 1);
+      eTypeParameter.writeXMI(b, "eTypeParameters", indentationLevel + 1, false, false);
     }
     for (EParameter eParameter : getEParameterList()) {
-      eParameter.writeXMI(b, "eParameters", indentationLevel + 1);
+      eParameter.writeXMI(b, "eParameters", indentationLevel + 1, false, false);
     }
 
     // closing tag
@@ -257,9 +349,9 @@ aspect XMIWriter {
     b.append(">\n");
   }
 
-  void EParameter.writeXMI(StringBuilder b, String context, int indentationLevel) {
+  void EParameter.writeXMI(StringBuilder b, String context, int indentationLevel, boolean topLevel, boolean requiresType) {
     b.append(indentString(indentationLevel)).append("<");
-    startXMIElement(b, "", context);
+    startXMIElement(b, "", context, topLevel, requiresType);
     // attributes
     // from ENamedElement
     b.append(" name=\"").append(getName()).append("\"");
@@ -287,11 +379,11 @@ aspect XMIWriter {
     // child nodes
     // from EModelElement
     for (EAnnotation eAnnotation : getEAnnotationList()) {
-      eAnnotation.writeXMI(b, "eAnnotations", indentationLevel + 1);
+      eAnnotation.writeXMI(b, "eAnnotations", indentationLevel + 1, false, false);
     }
     // from ETypedElement
     if (hasEGenericType()) {
-      getEGenericType().writeXMI(b, "eGenericType", indentationLevel + 1);
+      getEGenericType().writeXMI(b, "eGenericType", indentationLevel + 1, false, false);
     }
 
     // closing tag
@@ -301,11 +393,11 @@ aspect XMIWriter {
   }
 
 
-  abstract void EStructuralFeature.writeXMI(StringBuilder b, String context, int indentationLevel);
+  abstract void EStructuralFeature.writeXMI(StringBuilder b, String context, int indentationLevel, boolean topLevel, boolean requiresType);
 
-  void EReference.writeXMI(StringBuilder b, String context, int indentationLevel) {
+  void EReference.writeXMI(StringBuilder b, String context, int indentationLevel, boolean topLevel, boolean requiresType) {
     b.append(indentString(indentationLevel)).append("<");
-    startXMIElement(b, "ecore:EReference", context);
+    startXMIElement(b, "ecore:EReference", context, topLevel, requiresType);
     // attributes
     // from ENamedElement
     b.append(" name=\"").append(getName()).append("\"");
@@ -362,11 +454,11 @@ aspect XMIWriter {
     // child nodes
     // from EModelElement
     for (EAnnotation eAnnotation : getEAnnotationList()) {
-      eAnnotation.writeXMI(b, "eAnnotations", indentationLevel + 1);
+      eAnnotation.writeXMI(b, "eAnnotations", indentationLevel + 1, false, false);
     }
     // from ETypedElement
     if (hasEGenericType()) {
-      getEGenericType().writeXMI(b, "eGenericType", indentationLevel + 1);
+      getEGenericType().writeXMI(b, "eGenericType", indentationLevel + 1, false, false);
     }
 
     // closing tag
@@ -375,9 +467,9 @@ aspect XMIWriter {
     b.append(">\n");
   }
 
-  void EAttribute.writeXMI(StringBuilder b, String context, int indentationLevel) {
+  void EAttribute.writeXMI(StringBuilder b, String context, int indentationLevel, boolean topLevel, boolean requiresType) {
     b.append(indentString(indentationLevel)).append("<");
-    startXMIElement(b, "ecore:EAttribute", context);
+    startXMIElement(b, "ecore:EAttribute", context, topLevel, requiresType);
     // attributes
     // from ENamedElement
     b.append(" name=\"").append(getName()).append("\"");
@@ -428,11 +520,11 @@ aspect XMIWriter {
     // child nodes
     // from EModelElement
     for (EAnnotation eAnnotation : getEAnnotationList()) {
-      eAnnotation.writeXMI(b, "eAnnotations", indentationLevel + 1);
+      eAnnotation.writeXMI(b, "eAnnotations", indentationLevel + 1, false, false);
     }
     // from ETypedElement
     if (hasEGenericType()) {
-      getEGenericType().writeXMI(b, "eGenericType", indentationLevel + 1);
+      getEGenericType().writeXMI(b, "eGenericType", indentationLevel + 1, false, false);
     }
 
     // closing tag
@@ -441,9 +533,9 @@ aspect XMIWriter {
     b.append(">\n");
   }
 
-  void EAnnotation.writeXMI(StringBuilder b, String context, int indentationLevel) {
+  void EAnnotation.writeXMI(StringBuilder b, String context, int indentationLevel, boolean topLevel, boolean requiresType) {
     b.append(indentString(indentationLevel)).append("<");
-    startXMIElement(b, "", context);
+    startXMIElement(b, "", context, topLevel, requiresType);
     // attributes
     b.append(" source=\"").append(getSource()).append("\"");
 
@@ -454,7 +546,7 @@ aspect XMIWriter {
     b.append(">\n");
     // child nodes
     for (EStringToStringMapEntry detail : getDetailList()) {
-      detail.writeXMI(b, "details", indentationLevel + 1);
+      detail.writeXMI(b, "details", indentationLevel + 1, false, false);
     }
 
     // closing tag
@@ -463,9 +555,9 @@ aspect XMIWriter {
     b.append(">\n");
   }
 
-  void EStringToStringMapEntry.writeXMI(StringBuilder b, String context, int indentationLevel) {
+  void EStringToStringMapEntry.writeXMI(StringBuilder b, String context, int indentationLevel, boolean topLevel, boolean requiresType) {
     b.append(indentString(indentationLevel)).append("<");
-    startXMIElement(b, "", context);
+    startXMIElement(b, "", context, topLevel, requiresType);
     // attributes
     b.append(" key=\"").append(getKey()).append("\"");
     b.append(" value=\"").append(getValue()).append("\"");
@@ -473,9 +565,9 @@ aspect XMIWriter {
     b.append("/>\n");
   }
 
-  void ETypeParameter.writeXMI(StringBuilder b, String context, int indentationLevel) {
+  void ETypeParameter.writeXMI(StringBuilder b, String context, int indentationLevel, boolean topLevel, boolean requiresType) {
     b.append(indentString(indentationLevel)).append("<");
-    startXMIElement(b, "", context);
+    startXMIElement(b, "", context, topLevel, requiresType);
     // attributes
     // from ENamedElement
     b.append(" name=\"").append(getName()).append("\"");
@@ -487,11 +579,11 @@ aspect XMIWriter {
     // child nodes
     // from EModelElement
     for (EAnnotation eAnnotation : getEAnnotationList()) {
-      eAnnotation.writeXMI(b, "eAnnotations", indentationLevel + 1);
+      eAnnotation.writeXMI(b, "eAnnotations", indentationLevel + 1, false, false);
     }
     // from ETypeParameter
     for (EGenericType eGenericType : getEBoundList()) {
-      eGenericType.writeXMI(b, "eTypeParameters", indentationLevel + 1);
+      eGenericType.writeXMI(b, "eTypeParameters", indentationLevel + 1, false, false);
     }
 
     // closing tag
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
index 53a6c3e4b75cbc7c39c1d7271b622dc80ed70b8f..a1bcae043d7973793d0ad07eadc1d61d434b1eeb 100644
--- a/src/main/java/de/tudresden/inf/st/e2j/parser/EcoreParser.java
+++ b/src/main/java/de/tudresden/inf/st/e2j/parser/EcoreParser.java
@@ -14,10 +14,7 @@ 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;
+import java.util.*;
 
 public class EcoreParser {
 
@@ -27,7 +24,7 @@ public class EcoreParser {
   private static Logger logger = LogManager.getLogger(EcoreParser.class);
   private final XMLInputFactory factory = XMLInputFactory.newInstance();
 
-  public EObject parse(InputStream stream) throws XMIParseException {
+  public List<EObject> parse(InputStream stream) throws XMIParseException {
 
     try {
       final XMLEventReader reader = factory.createXMLEventReader(stream);
@@ -43,8 +40,12 @@ public class EcoreParser {
           StartElement root = event.asStartElement();
 
           switch (root.getName().getLocalPart()) {
+            case "XMI":
+              return parseXMI(reader, Collections.EMPTY_MAP);
             case "EPackage":
-              return parseEPackage(reader, Collections.EMPTY_MAP);
+              EPackage ePackage = parseEPackage(reader, Collections.EMPTY_MAP);
+              ePackage.addPackage(ePackage);
+              return Collections.singletonList(ePackage);
             default:
               throw new XMIParseException("Unable to parse root element " + root.getName().toString());
           }
@@ -75,6 +76,76 @@ public class EcoreParser {
     return result;
   }
 
+  private List<EPackage> parseXMI(final XMLEventReader reader, Map<String, String> nameSpaces) throws XMLStreamException {
+
+    List<EPackage> contents = new ArrayList<>();
+
+
+    // 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()) {
+        default:
+          logger.warn("ignoring attribute {}:{}", attribute.getName().getPrefix(), attribute.getName().getLocalPart());
+      }
+    }
+
+    // parse the contained elements
+    while (reader.hasNext()) {
+      XMLEvent nextEvent = reader.peek();
+//      logger.debug("looking at ({}:{}) :'{};.", nextEvent.getLocation().getLineNumber(), nextEvent.getLocation().getColumnNumber(), nextEvent);
+      if (nextEvent.isStartElement()) {
+        if (nextEvent.isStartDocument()) {
+          reader.nextEvent();
+        } else if (nextEvent.isStartElement()) {
+          StartElement root = nextEvent.asStartElement();
+
+          switch (root.getName().getLocalPart()) {
+            case "EPackage":
+              contents.add(parseEPackage(reader, Collections.EMPTY_MAP));
+              break;
+            default:
+              throw new XMIParseException("Unable to parse root element " + root.getName().toString());
+          }
+        } else {
+          logger.error("the element is a {}", nextEvent.getEventType());
+          throw new XMIParseException("Element is not a start element!");
+        }
+
+      } else if (nextEvent.isEndElement() && nextEvent.asEndElement().getName().equals(startElement.getName())) {
+        reader.nextEvent();
+
+        for (EPackage ePackage: contents) {
+          for (EPackage sibling : contents) {
+            ePackage.addPackage(sibling);
+          }
+        }
+
+        return contents;
+      } else {
+        // ignore all other events
+        if (nextEvent.getEventType() != XMLStreamConstants.CHARACTERS)
+          logger.warn("ignoring event at ({}:{}) {}", nextEvent.getLocation().getLineNumber(), nextEvent.getLocation().getColumnNumber(), nextEvent);
+        reader.nextEvent();
+      }
+    }
+
+    // TODO throw exception
+
+    for (EPackage ePackage: contents) {
+      for (EPackage sibling : contents) {
+        ePackage.addPackage(sibling);
+      }
+    }
+
+    return contents;
+  }
+
   private EPackage parseEPackage(final XMLEventReader reader, Map<String, String> nameSpaces) throws XMLStreamException {
 
     EPackage ePackage = new EPackage();
@@ -115,6 +186,10 @@ public class EcoreParser {
           case "eAnnotations":
             ePackage.addEAnnotation(parseEAnnotation(reader, nameSpaces));
             break;
+          // from EPackage
+          case "eSubpackages":
+            ePackage.addESubPackage(parseEPackage(reader, nameSpaces));
+            break;
           default:
             logger.warn("ignoring element at ({}:{}) {}:{}", nextEvent.getLocation().getLineNumber(), nextEvent.getLocation().getColumnNumber(), nextElement.getName().getPrefix(), nextElement.getName().getLocalPart());
         }
@@ -378,9 +453,142 @@ public class EcoreParser {
     }
   }
 
-  private EClassifier parseEEnum(final XMLEventReader reader, Map<String, String> nameSpaces) throws XMLStreamException {
-    // TODO implement
-    return null;
+  private EEnum parseEEnum(final XMLEventReader reader, Map<String, String> nameSpaces) throws XMLStreamException {
+
+    EEnum eEnum = new EEnum();
+
+    // set default values
+    eEnum.setSerializable(true);
+
+    // 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:EEnum")) {
+          throw new XMIParseException("Expected ecore:EEnum but found " + attribute.getValue(), attribute.getLocation());
+        }
+      } else {
+        switch (attribute.getName().getLocalPart()) {
+          // from ENamedElement
+          case "name":
+            eEnum.setName(attribute.getValue());
+            break;
+          // from EClassifier
+          case "instanceClassName":
+            eEnum.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 EDataType
+          case "serializable":
+            eEnum.setSerializable(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.isStartElement()) {
+        final StartElement nextElement = nextEvent.asStartElement();
+        switch (nextElement.getName().getLocalPart()) {
+          case "eTypeParameters":
+            eEnum.addETypeParameter(parseETypeParameter(reader, nameSpaces));
+            break;
+          case "eAnnotations":
+            eEnum.addEAnnotation(parseEAnnotation(reader, nameSpaces));
+            break;
+          case "eLiterals":
+            eEnum.addELiteral(parseEEnumLiteral(reader, nameSpaces));
+            break;
+          default:
+            logger.warn("ignoring element {}:{}", nextElement.getName().getPrefix(), nextElement.getName().getLocalPart());
+        }
+      } else if (nextEvent.isEndElement() && nextEvent.asEndElement().getName().equals(startElement.getName())) {
+        reader.nextEvent();
+        return eEnum;
+      } else {
+        // ignore all other events
+        if (nextEvent.getEventType() != XMLStreamConstants.CHARACTERS)
+          logger.warn("in start element {}: ignoring event {}: '{}'",startElement.getName(), nextEvent.getEventType(), nextEvent.toString().replace("\n", "\\n"));
+      }
+
+      reader.nextEvent();
+      nextEvent = reader.peek();
+    }
+  }
+
+  private EEnumLiteral parseEEnumLiteral(final XMLEventReader reader, Map<String, String> nameSpaces) throws XMLStreamException {
+
+    EEnumLiteral eEnumLiteral = new EEnumLiteral();
+
+    // 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:EEnumLiteral")) {
+          throw new XMIParseException("Expected ecore:EEnumLiteral but found " + attribute.getValue(), attribute.getLocation());
+        }
+      } else {
+        switch (attribute.getName().getLocalPart()) {
+          // from ENamedElement
+          case "name":
+            eEnumLiteral.setName(attribute.getValue());
+            break;
+          // from EEnumLiteral
+          case "value":
+            eEnumLiteral.setValue(Integer.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.isStartElement()) {
+        final StartElement nextElement = nextEvent.asStartElement();
+        switch (nextElement.getName().getLocalPart()) {
+          case "eAnnotations":
+            eEnumLiteral.addEAnnotation(parseEAnnotation(reader, nameSpaces));
+            break;
+          default:
+            logger.warn("ignoring element {}:{}", nextElement.getName().getPrefix(), nextElement.getName().getLocalPart());
+        }
+      } else if (nextEvent.isEndElement() && nextEvent.asEndElement().getName().equals(startElement.getName())) {
+        reader.nextEvent();
+        return eEnumLiteral;
+      } else {
+        // ignore all other events
+        if (nextEvent.getEventType() != XMLStreamConstants.CHARACTERS)
+          logger.warn("in start element {}: ignoring event {}: '{}'",startElement.getName(), nextEvent.getEventType(), nextEvent.toString().replace("\n", "\\n"));
+      }
+
+      reader.nextEvent();
+      nextEvent = reader.peek();
+    }
   }
 
   private ETypeParameter parseETypeParameter(final XMLEventReader reader, Map<String, String> nameSpaces) throws XMLStreamException {
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
index 47b654ffa269bc23c6958070acdb5a3f60820e01..6635beae0bb32768a8d394ae7e05561000fdb026 100644
--- a/src/test/java/de/tudresden/inf/st/e2j/parser/ParserTest.java
+++ b/src/test/java/de/tudresden/inf/st/e2j/parser/ParserTest.java
@@ -2,16 +2,61 @@ 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.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.ArgumentsProvider;
+import org.junit.jupiter.params.provider.ArgumentsSource;
 
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintWriter;
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.util.stream.Stream;
 
 class ParserTest {
 
+
+  private static Logger logger = LogManager.getLogger(ParserTest.class);
+
+  @ParameterizedTest
+  @ArgumentsSource(EcoreFileProvider.class)
+  void parseEcore(String fileName) {
+
+    logger.info("Parsing file src/test/resources/ecore/zoo/{}", fileName);
+
+    EObject ePackage = null;
+
+    EcoreParser parser = new EcoreParser();
+
+    try (InputStream stream = this.getClass().getResourceAsStream("/ecore/zoo/" + fileName)) {
+      Assertions.assertNotNull(stream, "unable to load resource '" + fileName + "'");
+      ePackage = parser.parse(stream).get(0);
+    } catch (IOException | XMIParseException e) {
+      Assertions.fail(e);
+    }
+
+    Assertions.assertNotNull(ePackage);
+
+    Assertions.assertTrue(ePackage instanceof EPackage);
+
+    EPackage p = (EPackage) ePackage;
+
+    StringBuilder b = new StringBuilder();
+
+    logger.info("writing {} packages", p.getPackageList().size());
+    p.writeXMI(b, "ISO-8859-1");
+
+    try (PrintWriter out = new PrintWriter("src/test/resources/ecore/zoo-gen/" + fileName, StandardCharsets.ISO_8859_1.name())) {
+      out.print(b.toString());
+    } catch (FileNotFoundException | UnsupportedEncodingException e) {
+      Assertions.fail("unable to write output file", e);
+    }
+
+  }
+
   @Test
   void parseBigraph() {
 
@@ -23,7 +68,7 @@ class ParserTest {
 
     try (InputStream stream = this.getClass().getResourceAsStream(fileName)) {
       Assertions.assertNotNull(stream, "unable to load resource '" + fileName + "'");
-      ePackage = parser.parse(stream);
+      ePackage = parser.parse(stream).get(0);
     } catch (IOException | XMIParseException e) {
       Assertions.fail(e);
     }
@@ -58,7 +103,7 @@ class ParserTest {
 
     try (InputStream stream = this.getClass().getResourceAsStream(fileName)) {
       Assertions.assertNotNull(stream, "unable to load resource '" + fileName + "'");
-      ePackage = parser.parse(stream);
+      ePackage = parser.parse(stream).get(0);
     } catch (IOException | XMIParseException e) {
       Assertions.fail(e);
     }
@@ -82,4 +127,23 @@ class ParserTest {
     System.out.println(b.toString());
   }
 
+  public static class EcoreFileProvider implements ArgumentsProvider {
+
+    @Override
+    public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
+
+      try (InputStream stream = this.getClass().getResourceAsStream("/ecore/zoo")) {
+        return new BufferedReader(new InputStreamReader(stream))
+            .lines()
+            .filter(fileName -> fileName.endsWith(".ecore"))
+            .map(Arguments::of);
+      } catch (IOException e) {
+        Assertions.fail(e);
+      }
+
+      // no stream if something fails
+      return Stream.empty();
+    }
+  }
+
 }