# EMF Serialisierung XML



## emftester (23. Sep 2009)

Hallo zusammen,

EMF bereitet mir mal wieder etwas größere Kopfschmerzen und ich hoffe ihr könnt mir etwas helfen.

Mit folgendem Code erstelle ich dynamisch ein Package und speichere es dann als XML ab:

```
final EPackage poPackage = EcoreFactory.eINSTANCE.createEPackage();
		final EFactory poFactory = poPackage.getEFactoryInstance();

		final EClass purchaseOrderClass = createClass("PurchaseOrder", poPackage);
		final EClass itemClass = createClass("Item", poPackage);

		final EAttribute shipToAttribute = createAttribute("shipTo", purchaseOrderClass);
		final EReference itemsReference = createReference("items", itemClass, true, -1, purchaseOrderClass);

		final EAttribute itemNameAttribute = createAttribute("name", itemClass);

		final EObject aPurchaseOrder = poFactory.create(purchaseOrderClass);
		aPurchaseOrder.eSet(shipToAttribute, "123 Maple Street");

		final List items = (List) aPurchaseOrder.eGet(itemsReference);

		EObject aItem = poFactory.create(itemClass);
		aItem.eSet(itemNameAttribute, "Item 1");
		items.add(aItem);

		aItem = poFactory.create(itemClass);
		aItem.eSet(itemNameAttribute, "Item 2");
		items.add(aItem);

		final Resource resource1 = new GenericXMLResourceImpl(org.eclipse.emf.common.util.URI
				.createFileURI("C:/te.xml"));
		resource1.getContents().add(aPurchaseOrder);
		resource1.save(System.out, null);
```

Als Ergebnis erhalte ich:

```
<?xml version="1.0" encoding="ASCII"?>
<PurchaseOrder shipTo="123 Maple Street">
  <items name="Item 1"/>
  <items name="Item 2"/>
</PurchaseOrder>
```

Ich würde allerdings gerne folgendes Ergebnis haben:

```
<?xml version="1.0" encoding="ASCII"?>
<PurchaseOrder shipTo="123 Maple Street">
  <Item name="Item 1"/>
  <Item name="Item 2"/>
</PurchaseOrder>
```

Also den Namen der Klasse anstatt den Namen des Attributs der übergeordneten Klasse.
Kann ich dies irgendwie in EMF erzwingen?

Ich bin für jeden Tipp sehr dankbar.

Viele Grüße,
emftester


----------



## Wildcard (23. Sep 2009)

Sollte über EAnnotations funktionieren. Kannst du noch die drei fehlenden Methoden posten damit ich das mal eben an deinem Code verifizieren kann?


----------



## emftester (23. Sep 2009)

Hallo Wildcard,

hier sind noch die fehlenden drei Methoden. 


```
public EClass createClass(final String name, final EPackage toPackage) {
		final EClass clazz = EcoreFactory.eINSTANCE.createEClass();
		clazz.setName(name);
		toPackage.getEClassifiers().add(clazz);
		return clazz;
	}

	public EAttribute createAttribute(final String name, final EClass toClass) {
		final EAttribute attribute = EcoreFactory.eINSTANCE.createEAttribute();
		attribute.setName(name);
		attribute.setEType(EcorePackage.eINSTANCE.getEString());
		toClass.getEStructuralFeatures().add(attribute);
		return attribute;
	}

	public EReference createReference(final String name, final EClassifier type, final boolean containment,
			final int upperBound, final EClass toClass) {
		final EReference reference = EcoreFactory.eINSTANCE.createEReference();
		reference.setName(name);
		reference.setEType(type);
		reference.setContainment(containment);
		reference.setUpperBound(upperBound);
		toClass.getEStructuralFeatures().add(reference);
		return reference;
	}
```

Meinst du die ExtendedMetaData?

Ich hab z.B. auch das Problem, dass wenn ich einen Typ eines anderen Namespaces abspeichere, dieser z.B. im Format: <items xsi:type="otherNSPrefix:NewItem" name="Test"> abgespeichert wird.
Ich hoffe allerdings dieses Problem mit der Lösung des oberen Problems zu lösen.

Ich danke dir für deine Hilfe


----------



## Wildcard (23. Sep 2009)

Hier die Abwandlung:

```
public static void main(String[] args) throws IOException {
		final EPackage poPackage = EcoreFactory.eINSTANCE.createEPackage();
        final EFactory poFactory = poPackage.getEFactoryInstance();
 
        final EClass purchaseOrderClass = createClass("PurchaseOrder", poPackage);
        final EClass itemClass = createClass("Item", poPackage);
 
        final EAttribute shipToAttribute = createAttribute("shipTo", purchaseOrderClass);
        final EReference itemsReference = createReference("items", itemClass, true, -1, purchaseOrderClass);

//hier:
        EAnnotation annotation = EcoreFactory.eINSTANCE.createEAnnotation();
        annotation.setSource("http:///org/eclipse/emf/ecore/util/ExtendedMetaData");
        annotation.getDetails().put("name", "Item");
        itemsReference.getEAnnotations().add(annotation);
//
 
        final EAttribute itemNameAttribute = createAttribute("name", itemClass);
 
        final EObject aPurchaseOrder = poFactory.create(purchaseOrderClass);
        aPurchaseOrder.eSet(shipToAttribute, "123 Maple Street");
 
        final List items = (List) aPurchaseOrder.eGet(itemsReference);
 
        EObject aItem = poFactory.create(itemClass);
        aItem.eSet(itemNameAttribute, "Item 1");
        items.add(aItem);
 
        aItem = poFactory.create(itemClass);
        aItem.eSet(itemNameAttribute, "Item 2");
        items.add(aItem);
 
        final Resource resource1 = new GenericXMLResourceImpl(org.eclipse.emf.common.util.URI
                .createFileURI("te.xml"));
        resource1.getContents().add(aPurchaseOrder);
//und hier
        Map<String, Object> options = new HashMap<String, Object>();
        options.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE);
        resource1.save(System.out, options);

	}
```
Das Resultat sieht nun so aus:
[XML]<?xml version="1.0" encoding="ASCII"?>
<PurchaseOrder shipTo="123 Maple Street">
  <Item name="Item 1"/>
  <Item name="Item 2"/>
</PurchaseOrder>[/XML]

Auch wirklich komplexe Dinge sind mit ExtendedMetaData möglich, Informationen dazu gibt's hier:
http://www.eclipse.org/modeling/emf/docs/overviews/XMLSchemaToEcoreMapping.pdf
Ich würde dir allerdings raten das du dir einfach erstmal ein einfaches XSD bastelst das so aussieht wie du dein XML haben willst, dann ein ecore aus dem Schema erzeugen lässt und dieses Ecore dann als 'Spickzettel' für dynamisches EMF verwendest.


----------



## emftester (23. Sep 2009)

Mit XSD's habe ich es bereits probiert.
Allerdings habe ich da ein paar Probleme mit AnyType, dort muss ich ein Object eines anderen Namespaces in einer FeatureMap speichern, allerdings entsteht bei der Serialisierung, in etwa folgendes:
<items xsi:type="otherNSPrefix:NewItem" name="Test"> 
Und ich verstehe nicht warum.
Ich hab z.B. eine XML eingelesen, der Typ von otherNS wird auch gefunden und richtig interpretiert.
Wenn ich nun in die FeatureMap ein EstructuralFeature mit einem neuerstellten otherNS Typ hinzufüge und danach serialisiere, erhalte ich komischerweise bei dem eingelesenen otherNS Typ, das richtige Ergebnis und bei dem Neuerstellten erhalte ich die obige Serialisierung: <items xsi:type="otherNSPrefix:NewItem" name="Test"> 
und ich hätte dies gerne ohne die EMF-Type: <otherNSPrefix:NewItem name="Test">
Jetzt bin ich auf der Suche nach den Unterschieden, habe aber bisher keine gefunden.
EStructuralFeature schaut bei beiden gleich aus.
Deswegen habe ich jetzt beschlossen, dass ganze mehr oder weniger ganz von vorne aufzuziehen
und ein Problem nach dem anderen zu lösen.

Falls du noch irgendwelche Tipps hast auf die ich evtl. morgen achten soll,
so nehme ich sie sehr gerne an, ansonsten melde ich mich morgen nochmal,
falls ich mit meinem Problem weitergekommen bin.

Ich danke dir jedenfalls sehr für deine Hilfe.


----------



## Wildcard (24. Sep 2009)

Hmm, etwas in der Art habe ich mit EMF schon bei Ivy-XML gemacht. Dort ging es allerdings um anyAttribute. Ich schau mal ob ich das noch finde.


----------



## emftester (24. Sep 2009)

Hallo,

also ich bin für jeden Tipp dankbar, bin heute nicht wirklich weitergekommen.
Ich bin schon fast so weit meinen eigenen XML-Writer zu schreiben.


----------



## emftester (28. Sep 2009)

Hallo,

also ich bin jetzt schon etwas weitergekommen.
Ich schaffe es zumindest, dass ein weiterer Namespace in der XML angezeigt wird,
das Problem ist allerdings, dass es irgendwie als Resource verlinkt wird.


```
// Packages and classes
		final EPackage companyPackage = EcoreFactory.eINSTANCE.createEPackage();
		final EFactory companyFactory = companyPackage.getEFactoryInstance();
		companyPackage.setName("company");
		companyPackage.setNsPrefix("company");
		companyPackage.setNsURI("http://com.example/company");

		final EClass companyClass = createClass("Company", companyPackage);
		final EClass departmentsClass = createClass("Departments", companyPackage);
		addNameAnnotation("company", companyClass);
		addNameAnnotation("departments", departmentsClass);

		final EPackage personalPackage = EcoreFactory.eINSTANCE.createEPackage();
		final EFactory personalFactory = personalPackage.getEFactoryInstance();
		personalPackage.setName("personal");
		personalPackage.setNsPrefix("personal");
		personalPackage.setNsURI("http://com.example/company2/personal");

		final EClass personalClass = createClass("Personal", personalPackage);
		final EClass personalDataClass = createClass("PersonalData", personalPackage);

		// company features
		final EReference departmentsReference = createReference("departments", departmentsClass, true, 1, companyClass);

		final EAttribute anyAttribute = createAttribute("any", EcorePackage.Literals.EFEATURE_MAP_ENTRY,
				departmentsClass);
		anyAttribute.setLowerBound(0);
		anyAttribute.setUpperBound(-1);
		EAnnotation annotation = EcoreFactory.eINSTANCE.createEAnnotation();
		annotation.setSource("http:///org/eclipse/emf/ecore/util/ExtendedMetaData");
		annotation.getDetails().put("name", ":0");
		annotation.getDetails().put("kind", "elementWildcard");
		annotation.getDetails().put("wildcards", "##any");
		annotation.getDetails().put("processing", "lax");
		anyAttribute.getEAnnotations().add(annotation);

		final EReference personalReference = createReference("personal", personalClass, false, 1, departmentsClass);
		annotation = EcoreFactory.eINSTANCE.createEAnnotation();
		annotation.setSource("http:///org/eclipse/emf/ecore/util/ExtendedMetaData");
		annotation.getDetails().put("name", "personal");
		annotation.getDetails().put("kind", "element");
		personalReference.getEAnnotations().add(annotation);

		// personal feature
		final EReference personalDataReference = createReference("personalData", personalDataClass, true, 1,
				personalClass);

		final EAttribute personalDataNameAttribute = createAttribute("name", EcorePackage.Literals.ESTRING,
				personalDataClass);

	

		final EObject personal = personalFactory.create(personalClass);
		final EObject personalData = personalFactory.create(personalDataClass);
		personalData.eSet(personalDataNameAttribute, "Tester1");
		personal.eSet(personalDataReference, personalData);

		try {
			final Map options = new HashMap();
			options.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE);

			final ResourceSet resourceSet = new ResourceSetImpl();
			resourceSet.getPackageRegistry().put(companyPackage.getNsURI(), companyPackage);
			resourceSet.getPackageRegistry().put(personalPackage.getNsURI(), personalPackage);
			final Resource resource = resourceSet.createResource(org.eclipse.emf.common.util.URI
					.createFileURI("c:/myNS.txt"));

			resource.load(options);
			final EObject company = resource.getContents().get(0);

			final EObject departments = (EObject) company.eGet(departmentsReference);
			departments.eSet(personalReference, personal);
			resource.getContents().add(personal);

			final EObject dep = (EObject) company.eGet(departmentsReference);
			final FeatureMap map = (FeatureMap) dep.eGet(anyAttribute);
			// TODO:

			resource.save(new FileOutputStream("C:/out.xml"), options);
		} catch (final Exception e) {
			e.printStackTrace();
			
		}
```

myNS.txt:

```
<?xml version="1.0" encoding="utf-8"?>
<company xmlns="http://com.example/company">
	<departments>
		<department xmlns="http://com.example/company/dOne">
			<person name="Tester1" />
			<person name="Tester2" />
		</department>
		<department xmlns="http://com.example/company/dTwo">
			<person name="Tester3" />
			<person name="Tester4" />
		</department>
	</departments>
</company>
```

Nach der Ausführung erhalte ich:

```
<?xml version="1.0" encoding="UTF-8"?>
<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:company="http://com.example/company" xmlns:dOne="http://com.example/company/dOne" xmlns:dTwo="http://com.example/company/dTwo" xmlns:personal="http://com.example/company2/personal">
  <company:company>
    <departments>
      <dOne:department>
			<dOne:person name="Tester1"/>
			<dOne:person name="Tester2"/>
		</dOne:department>
      <dTwo:department>
			<dTwo:person name="Tester3"/>
			<dTwo:person name="Tester4"/>
		</dTwo:department>
      <personal>#/1</personal>
    </departments>
  </company:company>
  <personal:Personal>
    <personalData name="Tester1"/>
  </personal:Personal>
</xmi:XMI>
```

Hier wird mit <personal>#/1</personal> auf das Personal Namespace verwiesen.
Mein Wunschergebnis wäre allerdings folgendes:

```
<?xml version="1.0" encoding="UTF-8"?>
<company:company xmlns:xmi="http://www.omg.org/XMI" xmlns:company="http://com.example/company" xmlns:dOne="http://com.example/company/dOne" xmlns:dTwo="http://com.example/company/dTwo" xmlns:personal="http://com.example/company2/personal">
    <departments>
      <dOne:department>
			<dOne:person name="Tester1"/>
			<dOne:person name="Tester2"/>
		</dOne:department>
      <dTwo:department>
			<dTwo:person name="Tester3"/>
			<dTwo:person name="Tester4"/>
		</dTwo:department>
      <personal:Personal>
		<personalData name="Tester1"/>
	  </personal:Personal>
    </departments>
  </company:company>
```

Kann man dies irgendwie mit EMF erreichen?
Evtl. wäre es auch interessant, das Personal in das any-Attribute hinzuzufügen,
allerdings komme ich mit den FeatureMaps nicht klar, erhalte immer irgendwelche Exceptions.
Für mich wäre es sogar ideal, wenn ich es mit dem anyAttribute lösen könnte.

Hast du evtl. eine Idee wie ich das lösen könnte?


----------

