Welche API für komplexe XML-Struktur?

Dingels

Mitglied
Ich bin mir nicht sicher, ob mein Thema hier oder im XML-Unterforum besser aufgehoben ist. Bitte gegebenenfalls verschieben. Danke!

Hallo zusammen,

ich bin Student der Computerlinguistik und bin für ein Projekt von Python zu Java gewechselt, weil Java offensichtlich vielfältigere und mächtigere Werkzeuge hat, um XML-Daten zu verarbeiten. Genau davon möchte ich jetzt Gebrauch machen, allerdings weiß ich nicht, welche API für meine Zwecke die richtige ist. Ich hoffe, dass ihr mir dabei helfen könnt. Es geht dabei konkret um folgende Struktur:

[XML]<s id="s5">
<graph root="s5_504">
<terminals>
<t id="s5_1" word="Die" pos="ART" morph="Def.Fem.Nom.Sg"/>
<t id="s5_2" word="Tagung" pos="NN" morph="Fem.Nom.Sg.*"/>
<t id="s5_3" word="hat" pos="VVFIN" morph="3.Sg.Pres.Ind"/>
<t id="s5_4" word="mehr" pos="PIAT" morph="--"/>
<t id="s5_5" word="Teilnehmer" pos="NN" morph="Masc.Akk.Pl.*"/>
<t id="s5_6" word="als" pos="KOKOM" morph="--"/>
<t id="s5_7" word="je" pos="ADV" morph="--"/>
<t id="s5_8" word="zuvor" pos="ADV" morph="--"/>
</terminals>
<nonterminals>
<nt id="s5_500" cat="NP">
<edge label="NK" idref="s5_1"/>
<edge label="NK" idref="s5_2"/>
</nt>
<nt id="s5_501" cat="AVP">
<edge label="CM" idref="s5_6"/>
<edge label="MO" idref="s5_7"/>
<edge label="HD" idref="s5_8"/>
</nt>
<nt id="s5_502" cat="AP">
<edge label="HD" idref="s5_4"/>
<edge label="CC" idref="s5_501"/>
</nt>
<nt id="s5_503" cat="NP">
<edge label="NK" idref="s5_502"/>
<edge label="NK" idref="s5_5"/>
</nt>
<nt id="s5_504" cat="S">
<edge label="SB" idref="s5_500"/>
<edge label="HD" idref="s5_3"/>
<edge label="OA" idref="s5_503"/>
</nt>
</nonterminals>
</graph>
</s>[/XML]

Hierbei handelt es sich um einen Beispielsatz aus einem bestimmten Korpus, das ich benötige. Diese XML-Struktur bildet die syntaktische Struktur dieses Satzes in einer Art Baum ab. Kurz zur Erklärung: Die Terminal-Symbole sind einfache Wörter. Die Nonterminal-Symbole beschreiben einzelne Phrasen, die aus einigen dieser Wörter bestehen (z.B. bilden die Wörter "Die Tagung" eine Nominalphrase, kurz NP). Mehrere Phrasen lassen sich dann wiederum als eine größere Phrase zusammenfassen usw. bis man am Root-Symbol angekommen ist.

Mein Problem besteht jetzt darin, dass die Nonterminal-Symbole in der XML-Datei leider nicht direkt schon als Baum kodiert sind, sondern nur Referenzen auf andere (Non)terminal-Symbole beinhalten (siehe Attribut
Code:
idref
). Die begrenzten XML-Fähigkeiten von Python (und von mir 😀) konnten mir leider nicht helfen.

Frage: Mit welcher API kann ich die ursprüngliche syntaktische Struktur dieses Satzes als Baum am einfachsten einlesen? Die resultierende Datenstruktur ist nicht so wichtig. Die Hauptsache ist, dass ich für jeden Knoten im Baum die Mutter- und Tochterknoten auslesen kann (inklusive Annotation). Auch möchte ich gerne den Pfad von einem beliebigen Knoten zu einem anderen auslesen können.

Wie mache ich das am einfachsten und mit möglichst wenig Aufwand? Habt ihr einen Rat für mich?

Herzlichen Dank im Voraus! 🙂


EDIT: Anbei noch kurz zur Illustration, wie ich mir das Endergebnis in etwa vorstelle (ähnelt jetzt mehr einer Python-Datenstruktur, aber es sollte dennoch verständlich sein).

Code:
[ 'S',
    [ ('SB', 'NP'),
        [ ('NK', 'ART'), 'Die' ],
        [ ('NK', 'NN'), 'Tagung' ]
    ],
    [ ('HD', 'VVFIN'), 'hat' ],
    [ ('OA', 'NP'),
        [ ('NK', 'AP'),
            [ ('HD', 'PIAT'), 'mehr' ],
            [ ('CC', 'AVP'),
                [ ('CM', 'KOKOM'), 'als' ],
                [ ('MO', 'ADV'), 'je' ],
                [ ('HD', 'ADV'), 'zuvor' ]
            ]
        ],
        [ ('NK', 'NN'), 'Teilnehmer' ]
    ]
]
 
Zuletzt bearbeitet:
Wenn die Dateien nicht zu groß (50mb+) sind, dann empfehle ich JDOM.

Von StAX/SAX würde ich hier definitiv abraten, da es keine zusammenhänge erkennt. Es weißt noch nicht mal wo es sich gerade in der Datei befindet. Außerdem kann es nur nach vorne/unten "gehen" und nicht zurückspringen. Kurz gesagt: StAX/SAX ist Event-basierend und arbeitet seriell und ist nicht für deine Anforderungen geignet.

Über DOM/JDOM kannst du dir die Struktur des Baumes "angucken" und beliebig im Dokument "rumspringen", da die ganze Datei in den Speicher geladen wird. Auch die Pfade von einem bis zu einem anderen Element, kannst du bestimmen. Was die Referenzen auf andere "Variablen" etc angeht, kann ich es dir aber leider nicht sagen. Hatte nur wenig mit JDOM zu tun gehabt.
 
Zuletzt bearbeitet:
Aber um XPath nutzen zu können, musst du das Dokument ja mit DOM/JDOM einlesen/laden, dann kannst du erst suchen oder dich zum gewünschten Element bewegen, oder etwa nicht? 🙂
 
Wenn die Dateien nicht zu groß (50mb+) sind, dann empfehle ich JDOM.

Von StAX/SAX würde ich hier definitiv abraten, da es keine zusammenhänge erkennt. Es weißt noch nicht mal wo es sich gerade in der Datei befindet. Außerdem kann es nur nach vorne/unten "gehen" und nicht zurückspringen. Kurz gesagt: StAX/SAX ist Event-basierend und arbeitet seriell und ist nicht für deine Anforderungen geignet.

Über DOM/JDOM kannst du dir die Struktur des Baumes "angucken" und beliebig im Dokument "rumspringen", da die ganze Datei in den Speicher geladen wird. Auch die Pfade von einem bis zu einem anderen Element, kannst du bestimmen. Was die Referenzen auf andere "Variablen" etc angeht, kann ich es dir aber leider nicht sagen. Hatte nur wenig mit JDOM zu tun gehabt.

Ah danke, das hilft mir schon mal weiter. Richtig, der entsprechende Parser muss für meine Zwecke in der Lage sein, die Referenzen auf andere (Non)terminal-Symbole auszulesen und diese dann in einer Art Baum zu kodieren. Aber ich vermute, dass das keine API out-of-the-box beherrscht, oder? ???:L

EDIT: Habe in meinem ersten Posting noch eine Darstellung ergänzt, wie ich mir in etwa das Endergebnis vorstelle.
 
Zuletzt bearbeitet:
Aber um XPath nutzen zu können, musst du das Dokument ja mit DOM/JDOM einlesen/laden, dann kannst du erst suchen oder dich zum gewünschten Element bewegen, oder etwa nicht? 🙂

Ich finde, du kannst angenehmer durch die zweige iterieren. Wenn du eine ID gefunden hast, ist es auch einfach, das zugehörige terminal-objekt zu finden. Ich finde es angenehmer mit XPath zu arbeiten. Für manche Dinge wäre zwar ein direktes Arbeiten am DOM effizienter, aber meine XML-Files waren halt immer klein.
 
@Tomate
Naja falls du meinst, dass du XPath-Abfragen, wie bei einer Datenbank, immer gleich direkt auf den XML-Dokumenten aufrufst. Das halte ich in 90% der Fälle für eine ganz schlechte Idee.

Ich würde JDOM nehmen. Die API ist an einigen Stellen zwar etwas blöde, aber man kann wunderbar einfach Wrapper-Klassen um das JDOM Element Objekt bauen. So kannst du alle Dokumente zum Start als Objekte laden und kannst selber bestimmen wann du wieder persistierst. Hängt auch von der Menge der Daten ab. Man kann dann auch relativ gut mit einem AbstractDao arbeiten, der wenn geschickt implementiert, grundsätzlich alle XML-Dokumente verwalten kann.
 
Nö. Ich lasse mir eigentl. immer (bis auf einmal, da war ich aber echt faul 😀) eine NodeListe zurückgeben und arbeite dann mit dieser. (Kurz info: bei mir sind es immer ReadOnly-Zugriffe, aber darum geht es nicht).

Man könnte hier auch noch JAXB nennen.
 
Na super, jetzt wurden vermutlich fast alle wichtigen APIs mindestens einmal genannt. 😉 Das hilft mir jetzt nicht so wirklich weiter, außer der Hinweis, dass Sax/Stax ungeeignet sei.

Was ich von euch wissen möchte, ist nicht welche API ihr grundsätzlich am liebsten benutzt, sondern welche API sich am besten für mein Problem eignet. Das Problem ist, die
Code:
idref
-Referenzen in den Nonterminal-Symbolen korrekt aufzulösen und eine baumartige Struktur für die Symbole zu erhalten. :bahnhof:

Kann das eines der genannten APIs denn zumindest im Ansatz? Ich habe nicht die Zeit, mich in alle APIs einzulesen. Spontan würde ich sagen, mit JAXB habe ich den geringsten Aufwand, weil hier vieles automatisch läuft. Aber produziert es auch das beste Ergebnis? Kann da jemand aus Erfahrung sprechen?

Danke!
 
Das kann keine der APIs per se ohne dass du selbst was dafür tust.
Du musst dir das dann selbst in eine neue Objekt-Struktur mappen. Das geht mit JDOM eben z. B. indem du Wrapper-Klassen schreibst. JAXB geht natürlich auch. Im Endeffekt spart es dir Arbeit, aber ob du damit dass was du im Endeffekt erreichen willst am besten umsetzt kann ich dir momentan nicht sagen.
 
Zuletzt bearbeitet:
Das kann keine der APIs per se ohne dass du selbst was dafür tust.
Du musst dir das dann selbst in eine neue Objekt-Struktur mappen. Das geht mit JDOM eben z. B. indem du Wrapper-Klassen schreibst. JAXB geht natürlich auch. Im Endeffekt spart es dir Arbeit, aber ob du damit dass was du im Endeffekt erreichen willst am besten umsetzt kann ich dir momentan nicht sagen.

OK, das hab ich schon vermutet. 🙁 Danke jedenfalls. Ich werde mich mal mit JDOM auseinandersetzen.

Weitere Tipps und Kommentare nehme ich aber weiterhin gern entgegen. 🙂
 
Also so weit ich weiß, wird dir kein Parser deine Werte von idref, irgendwie mit id verknüpfen, um da die Werte auszulesen, wenn du das meinst. Wenn du von dem Element edge, die idref abfragst, wirst du nur den Wert der da steht bekommen, also s5_1 oder so ähnliches. Das, was du womit und wann verknüpfst, ist dann deine Aufgabe, das wird kein Parser für dich übernehmen. Aber wie schon gesagt wurde. Du kannst dir über JDOM, oder wie auch immer, alle Elemente der Datei liefern. Und was du dann mit den Elementen machst, ist dann dir überlassen.
 
Ich hab hier ein Back End für XML mit SaxParser und JDOM als AbstractDao umgesetzt rummfliegen. Vorausgesetzt Generics sagen dir was. Bei Interesse PN an mich.
 
Ich hab hier ein Back End für XML mit SaxParser und JDOM als AbstractDao umgesetzt rummfliegen. Vorausgesetzt Generics sagen dir was. Bei Interesse PN an mich.

Hast ne PN. 😉

Meines wissens ist das einzige XML Framework das wirklich mit dieser Art non-containment Referenz umgehen kann EMF.
Eclipse Modeling Framework ? Wikipedia

Interessant. Danke für den Hinweis. Funktioniert aber, wie der Name schon sagt, offensichtlich nur in Eclipse, oder? Ich arbeite nämlich mit Intellij IDEA.
 
Du brauchst Eclipse um die Klassen zu generieren und das Ecore zu erzeugen. Sobald du das einmal hast brauchst du kein Eclipse mehr.
Ich war mal so frei das ganze zu machen. Erst erzeugst du ein Schema für deine Instanz:
[XML]<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://www.example.org/graph"
elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.example.org/graph" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore">

<complexType name="s">
<sequence>
<element name="graph" type="tns:graph"></element>
</sequence>
<attribute name="id" type="ID"></attribute>
</complexType>

<complexType name="graph">
<sequence>
<element name="terminals" type="tns:terminals"></element>
<element name="nonterminals" type="tns:nonterminals"></element>
</sequence>
<attribute name="root" type="string"></attribute>
</complexType>

<complexType name="terminals">
<sequence>
<element name="t" type="tns:t" maxOccurs="unbounded"
minOccurs="1"></element>
</sequence>
</complexType>

<complexType name="nonterminals">
<sequence>
<element name="nt" type="tns:nt" maxOccurs="unbounded"
minOccurs="1"></element>
</sequence>
</complexType>

<complexType name="nt">
<complexContent>
<extension base="tns:symbol">
<sequence>
<element name="edge" type="tns:edge" maxOccurs="unbounded"
minOccurs="1">
</element>
</sequence>
<attribute name="cat" type="string"></attribute>
</extension>
</complexContent>
</complexType>

<complexType name="symbol" abstract="true">
<attribute name="id" type="ID"></attribute>
</complexType>

<complexType name="t">
<complexContent>
<extension base="tns:symbol">
<attribute name="id" type="ID"></attribute>
<attribute name="word" type="string"></attribute>
<attribute name="pos" type="string"></attribute>
<attribute name="morph" type="string"></attribute>
</extension>
</complexContent>
</complexType>

<complexType name="edge">
<attribute name="label" type="string"></attribute>
<attribute name="idref" type="IDREF" ecore:reference="tns:symbol"></attribute>
</complexType>

<element name="s" type="tns:s"></element>
</schema>[/XML]

Dann lässt du dir von EMF ein genmodel aus der XSD erzeugen und drückst auf 'generate' um die Java Klassen zu bekommen.
Anschließend ein kleines Sample um deine Beispieldatei einzulesen:
Java:
	public static void main(String[] args) throws FileNotFoundException, IOException {
		GraphXMLProcessor p = new GraphXMLProcessor();
		Resource resource = p.load(new FileInputStream("example.xml"), null);
		DocumentRoot root = (DocumentRoot) resource.getContents().get(0);
		S theS = root.getS();
		Nonterminals nonTerminals = theS.getGraph().getNonterminals();
		EList<Nt> nts = nonTerminals.getNt();
		for (Nt nt : nts) {
			for (Edge edge : nt.getEdge()) {
				Symbol symbol = edge.getIdref();
				if (symbol instanceof T) {
					T t = (T) symbol;
					System.out.println(t.getWord());					
				}
				else if (symbol instanceof Nt) {
					Nt nt2 = (Nt) symbol;
					System.out.println(nt2.getCat());
				}
					
			}
		}
	}

Ergibt:
Code:
Die
Tagung
als
je
zuvor
mehr
AVP
AP
Teilnehmer
NP
hat
NP
Das schöne ist, du brauchst keine Zeile java code zu schreiben, alles funktioniert automatisch.
Das XSD sollte allerdings noch etwas annotiert werden um schönere Java Klassennamen und getter zu bekommen.
Wie du siehst dauert das nicht mehr als ein paar Minuten.
 
Ach so, wichtig ist vor allem diese Annotation:
Code:
ecore:reference="tns:symbol
Damit weiß EMF das du dich nicht für den Wert von idref interessierst, sondern das du es als echte Referenz behandeln willst. Symbol ist in diesem Fall ein abstrakter Type damit t und nt eine gemeinsame Basisklasse bekommen.
 
@Wildcard:

Vielen Dank, das hast Du wirklich sehr anschaulich erklärt. :toll: Ich hatte mich gestern etwas mit JAXB beschäftigt; EMF scheint demnach ähnlich zu funktionieren. Das sieht wirklich nach einer heißen Spur aus. Ich werde mir das am Wochenende mal anschauen und dann hier noch mal eine Rückmeldung geben. 🙂
 
EMF ist um viele Klassen besser als JAXB, leider auch proportional weniger bekannt :autsch:
Ausserdem sind sie vom Ansatz her unterschiedlich. JAXB ist ein XML Binding Framework, EMF ist ein general purpose Modellierungswerkzeug für MDD. XML Binding ist dabei nur ein Use-Case von vielen.
Wie gesagt, die XSD alleine reicht schon völlig um ohne eine Zeile Code zu schreiben den Objektgraphen richtig zu deserialisieren (serialisieren funktioniert damit übrigens auch automatisch).
Du musst nur noch ein paar Annotations anbringen damit der generierte Code nicht so hässlich benamst wird.
So zum Beispiel sieht es dann gleich viel besser aus:
Java:
		EList<NonTerminal> nts = nonTerminals.getNonTerminals();
		for (NonTerminal nt : nts) {
			for (Edge edge : nt.getEdge()) {
				Symbol symbol = edge.getSymbol();
				if (symbol instanceof Terminal) {
					Terminal t = (Terminal) symbol;
					System.out.println(t.getWord());					
				}
				else if (symbol instanceof NonTerminal) {
					NonTerminal nonTerminal = (NonTerminal) symbol;
					System.out.println(nonTerminal.getCategory());
					
				}
					
			}
		}


[XML]<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://www.example.org/graph"
elementFormDefault="qualified" xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.example.org/graph" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore">

<complexType name="s">
<sequence>
<element name="graph" type="tns:graph"></element>
</sequence>
<attribute name="id" type="ID"></attribute>
</complexType>

<complexType name="graph">
<sequence>
<element name="terminals" type="tns:terminals"></element>
<element name="nonterminals" type="tns:nonterminals"></element>
</sequence>
<attribute name="root" type="string"></attribute>
</complexType>

<complexType name="terminals">
<sequence>
<element name="t" type="tns:t" maxOccurs="unbounded"
minOccurs="1" ecore:name="terminal"></element>
</sequence>
</complexType>

<complexType name="nonterminals">
<sequence>
<element name="nt" type="tns:nt" maxOccurs="unbounded"
minOccurs="1" ecore:name="nonTerminals"></element>
</sequence>
</complexType>

<complexType name="nt" ecore:name="NonTerminal">
<complexContent>
<extension base="tns:symbol">
<sequence>
<element name="edge" type="tns:edge" maxOccurs="unbounded"
minOccurs="1">
</element>
</sequence>
<attribute name="cat" type="string" ecore:name="category"></attribute>
</extension>
</complexContent>
</complexType>

<complexType name="symbol" abstract="true">
<attribute name="id" type="ID"></attribute>
</complexType>

<complexType name="t" ecore:name="Terminal">
<complexContent>
<extension base="tns:symbol">
<attribute name="word" type="string"></attribute>
<attribute name="pos" type="string"></attribute>
<attribute name="morph" type="string"></attribute>
</extension>
</complexContent>
</complexType>

<complexType name="edge">
<attribute name="label" type="string"></attribute>
<attribute name="idref" type="IDREF" ecore:reference="tns:symbol" ecore:name="symbol"></attribute>
</complexType>

<element name="s" type="tns:s"></element>
</schema>[/XML]
 
Zuletzt bearbeitet:
@Wildcard:

Ich habe mir EMF gerade mal angeschaut und installiert, aber ich hab keine Ahnung, wie ich aus meiner XML-Korpusdatei nun das XSD-Schema erstellen lassen kann. Im Netz finde ich nur Anleitungen, aus einer bestehenden XSD ein EMF Model zu erstellen, aber nicht wie ich überhaupt erst mal die XSD erstelle. Wie geht das? ???:L

Folgende Schritte habe ich jetzt gemacht:
1. Eine frische Version von Eclipse Indigo installiert.
2. Über den "Install New Software"-Assistenten und diese URL das EMF SDK 2.5.0 (EMF+XSD) installiert (da war ein Haufen an Optionen zur Auswahl, ich hab einfach die aktuellste Version genommen :bahnhof🙂
3. Ein leeres EMF Projekt erstellt.

Und nun? Ich habe die Möglichkeit, mir ein leeres XSD Model, ein Ecore Model oder ein EMF Generator Model erstellen zu lassen. Alle drei habe ich ausprobiert, aber ich finde nirgends die Option, mir eine XSD automatisch erstellen zu lassen.

Kannst Du mir das bitte schnell erklären? Das auf Wikipedia verlinkte EMF-Tutorial ist mir dazu leider auch keine Hilfe.

Danke! 🙂
 
Eine XSD schreibt man händisch. Ich habe dir oben eine gepostet die auf deine Instanzdaten passt.

Ah, ok, das wusste ich nicht. Hab ich aber vermutet, weil ich dazu keine Infos fand. Gut, dann werd ich es mal mit deine XSD versuchen. Hab aber entdeckt, dass es andere Tools gibt, die aus einer XML-Datei ein Schema erzeugen können. Die werde ich auch mal testen, weil es in meinem Korpus noch ein paar Sonderfälle gibt, die über mein gepostetes Beispiel hinausgehen.

Bei Problemen melde ich mich noch mal. 🙂
 
Hab aber entdeckt, dass es andere Tools gibt, die aus einer XML-Datei ein Schema erzeugen können.
Ja, die gibt es, die erzeugen aber eine XSD die auf genau eine Instanz passen, nicht notwendigerweise (und sogar meistens) nicht auf alle. Ein Schema schreibt man von Hand, das ist ein wichtiger Teil der Dokumentation und definiert auch gleich eine Schnittstelle für die Aussenwelt.
 
@Wildcard:

Sorry, dass ich mich erst jetzt melde, aber ich hatte keine Zeit, die EMF-Geschichte früher auszuprobieren. Ich hab das ganze jetzt getestet, und kann mir auch die Java-Klassen generieren lassen. Ich habe jetzt für jedes XML-Element (Edge, Terminal, NonTerminal usw.) jeweils eine Klasse und zusätzlich noch die Unterordner impl, util und validation.

Frage 1: Welche Klassen und Subklassen brauche ich jetzt überhaupt, und welche kann ich bedenkenlos löschen? Ich möchte nämlich einfach nur meine XML-Daten einlesen, also deserialisieren.

Frage 2: Du hattest mir ja ein Testskript geschrieben, mit dem ich meine Daten einlesen kann. Das Problem ist jetzt, dass in jeder der generierten Java-Klassen bestimmte Eclipse-eigene Klassen importiert werden, z.B.
Code:
import org.eclipse.emf.ecore.EObject;
. Auf diese Klassen kann ich in Intellij IDEA aber nicht zugreifen. Ist das ganze jetzt doch an Eclipse gebunden? :bahnhof: Und wo baue ich jetzt genau dein Testskript ein?

Ich weiß, ich könnte auch die EMF-Doku lesen, aber die erschlägt einen regelrecht. Ich hab mittlerweile auch ein anderes Korpus für mein Projekt gefunden, also notfalls kann ich darauf ausweichen, falls mir das hier zu kompliziert wird. Und danach sieht es momentan aus...

Wäre echt froh über weitere Hilfe. Besten Dank! 🙂
 
Frage 1: Welche Klassen und Subklassen brauche ich jetzt überhaupt, und welche kann ich bedenkenlos löschen? Ich möchte nämlich einfach nur meine XML-Daten einlesen, also deserialisieren.
Warum solltest du Klassen löschen wollen?
Auf diese Klassen kann ich in Intellij IDEA aber nicht zugreifen. Ist das ganze jetzt doch an Eclipse gebunden? Und wo baue ich jetzt genau dein Testskript ein?
Nein, es ist nicht an Eclipse gebunden, aber du musst EMF natürlich in den Classpath aufnehmen.
Verwendest du Maven? Die benötigten EMF Jars liegen auf Maven Central.
Falls nein, kannst du sie aus dem plugins Verzeichnis herauskopieren.
EMF/FAQ - Eclipsepedia
 

Zurück
Oben