Klassen Baumstruktur aus XMls erstellen, aber wie?

Hallo zusammen,

ich bin neu hier und habe gleich eine Frage. Jedoch erstmal zur Problematik:

Ich möchte einen Baum erstellen, den es später in eine Datei zu schreiben gilt. In diesem Baum kann es 3 unterschiedliche Knotentypen geben: Artikel, Dokument und Datei.

Ein Artikel kann wiederum aus mehreren Artikeln bestehen, ebenso kann ein Dokument aus mehreren Dokumenten bzw. Dateien bestehen.
Hinzu kommt, dass einem Artikel auch ein oder mehrere Dokumente zugeordnet sein können.

Die Informationen darüber, wie was zugeordnet wird, stehen in XML Dateien, die ich parsen möchte.

Hier ein Codeschnipsel aus der XML-Datei, in der alle Artikel stehen:
[XML]
<ART>
<ID>962085</ID>
<PART_NAME>Hubabubaluba</PART_NAME>
<LINK_ART>xml/art_962085.xml</LINK_ART>
</ART>

<ART>
<ID>962084</ID>
<PART_NAME>test</PART_NAME>
<LINK_ART>xml/art_962084.xml</LINK_ART>
</ART>
[/XML]

Und hier der Schnipsel eines der beiden Artikel (xml/art_962085.xml):
[XML]
<ART-SINGLE>
<ID>962085</ID>
<PART_NAME>Hubabubaluba</PART_NAME>
<LINK_ART>xml/art_962085.xml</LINK_ART>
<LINK_BOM>xml/art_bom_962085.xml</LINK_BOM>

</ART-SINGLE>
[/XML]

Mein Parser zum Lesen der XML-Datein sieht wie folgt aus:
Java:
package core;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;
/**
 * Klasse um XML Dateien zu parsen.
 * @author GetStringFrmObj
 *
 */
public class XMLparser {
	/**
	 * XML Datei, die geparst werden soll
	 */
	private File f;
	/**
	 * XML-Tag, von dem der Pfad + Dateiname extrahiert werden soll
	 */
	private String tag;
	/**
	 * String Liste, in der alle Pfade und Dateinamen stehen
	 */
	public List<String> str_list = new ArrayList<String>();
	
	/**
	 * Konstruktor, dem eine Quelldatei und das Tag übergeben werden müssen und das Ergebnis in die Liste schreibt.
	 * @param src
	 * @param tag
	 * @throws XMLStreamException
	 */
	public XMLparser(File src, String tag) throws XMLStreamException{
		this.f = src;
		this.tag = tag;
		
		  XMLInputFactory inputFactory = XMLInputFactory.newInstance();
	      XMLStreamReader stax = inputFactory.createXMLStreamReader( new StreamSource(f) ) ; //öffnet übergebene Datei
	      StringBuffer    sb = new StringBuffer();
	      int             state = 0;
		
	      while( stax.hasNext() ) {
	          stax.next();
	          String  name = ( stax.hasName() ) ? stax.getName().getLocalPart().trim() : null;
	          String  text = ( stax.hasText() ) ? stax.getText().trim() : null;
	             if( stax.hasName() && name.equals(tag) ) {
	              String s = stax.getElementText();
	              str_list.add(s);
	              
	           }
	      }
	      //Hier müsste der Code stehen, der für jeden der Artikel einen Knoten im Baum erstellt und    ihn an die Wurzel oder einen anderen Artikel/Dokument anhängt.
	      
	}
	
	public void printList(){
		System.out.println(str_list.toString());
	}
	
	public List<String> getList(){
		return str_list;
	}

	
}

Meine Frage lautet nun: Wie baue ich am intelligentesten einen Baum auf, der auch mit einer großen Menge an Artikeln, Dokumenten und Dateien zurecht kommt (Anzahl der zu parsenden Datein: ca. 50.000)

Vielen Dank für eure Unterstützung im Vorraus
 
Zuletzt bearbeitet:
Schau zum Bleistift mal hier rein
XML-Parser Grundlegendes

Wenn ich Dich richtig verstehe, dann solltest Du einen DOM-Parser (DOM = Document Object Model) verwenden.
Da gibt es für Java verschiedene fertige Lösungen. Es ist eine Weile her, dass ich soetwas verwendet habe, also such Dir was Aktuelles.
(Ich hab mal Xerxes von der Apache-Group verwendet, aber vielleicht gibts ein anderes angesagtes Mittel.)
Vielleicht gibts ja hier noch eine Empfehlung, wenn Du konkreter danach fragst. (lange Texte schrecken leider oft ab)
 
Zuletzt bearbeitet:
es gibt 2 grundlegende Möglichkeiten.

1. man verwendet das DOM von Java. Dabei erstellt man ein neues Dokument in Speicher, liest die XML-Dateien nacheinander per DOM ein und hängt diese in das Dokument. Der Vorteil dieser Methode wäre, dass die Struktur schon vorgegeben wäre, man leicht mir XPath darauf arbeiten könnte und das Schreiben in eine Datei wäre einfach.

2. man erstellt eine eigene Baumstruktur, mit den benötigten Knoten als eigene Objekte. Mit SAX oder StAX liest man die Dateien nacheinander ein, konvertiert die Inhalte in eigene Knoten und hängt diese in den eigenen Baum. Der Vorteil dieser Methode wäre, sie wäre platzsparender und schneller als DOM. Das Schreiben in eine Datei müsste man aber selber schreiben.

Slawa
 
Hallo slawaweis,

Variante 2 ist genau das, was ich umsetzen möchte, da DOM für die vorraussichtliche Menge an Daten zu langsam ist. Meiner Auffassung nach müsste ich das mit generischen Knoten lösen, oder liege ich da falsch?

meine Idee in Code ausgedrückt würde in etwa so aussehen:
Java:
package core;

import java.util.ArrayList;

/**
 * Ein einfacher Knoten in einem Baum.
 * 
 * Diese Klasse repräsentiert einen Knoten in einem Baum und verweist auf den Vaterknoten.
 * @author GetStringFrmObj
 * @version 0.1
 *
 */
public class Node<T> {
	/**Knotentyp: Entweder Artikel, Dokument oder Datei */
	private String _type;
	/**Nächster Knoten. Stellt den Vater eines Knotens dar */
	private Node<T> _parent;
	/**XML Datei des Knotens */
	private String _xmlfile;
	/**Kennzeichnet ob dieser Knoten der Wurzelknoten des Baumes ist */
	private Boolean _isRoot = false;
	/**Knotenliste der Kindsknoten dieses Knotens */
	private ArrayList<Node<T>> _childNodes = new ArrayList<Node<T>>();
	/** Level gibt an, auf welcher Ebene des Baumes sich der Knoten befindet. Je höher der Level, desto tiefer im Baum: 0 = root*/
	private int _level;
	/**Dummy-ID, soll vom IDgen pro konstruiertem Knoten überschrieben werden */
	private int _ID=-999;
	
	/**
	 * Konstruktor für einen Knoten
	 * @param type
	 * @param file
	 * @param n
	 */
	public Node(String type, String file){
		_type = type;
		_xmlfile = file;
		_isRoot = false;
		_parent = null;
		IDgen gen = new IDgen();
		_ID = gen.getID();
	}
	/**
	 * Konstruktor für einen Wurzelknoten
	 * @param type
	 */
	public Node(String type){
		try{
		if(type =="root"){
			_type = type;
			_parent = null;
			_xmlfile="";
			_isRoot = true;
			_ID = 0;
			_level = 0;
		}
		else{
		throw new IllegalArgumentException();
		}
		}
		catch(IllegalArgumentException x){
			System.err.println("Dieser Typ ist unbekannt.");
		}
	}
	
	/**
	 * Diese Methode liefert den nächsten Knoten zurück.
	 * @return
	 */
		
	/**
	 * Diese Methode liefert den Namen der XML Datei des Knotens.
	 * @return
	 */
	public String getFileName(){
		return _xmlfile;
	}
	public String getType(){
		return _type;
	}
	
	public Boolean isRoot(){
		return _isRoot;
	}
	
	public void setParent(Node p){
		this._parent = p;
	}
	
	public Integer getID(){
		return _ID;
	}
	
	public Integer getLevel(){
		return _level;
	}
	
	public void addChildNode(Node<T> n){
		try{
			if(n.getType()=="root")throw new IllegalArgumentException();
			else {
				_parent = this;
				_level = n.getLevel()+1;
				_childNodes.add(n);
			}
		}
		catch(IllegalArgumentException x){
			System.err.print("Der Wurzelknoten kann nicht Kind eines anderen Knotens sein!");
		}
	}
	
	public void printNode(){
		System.out.print("Typ: "+ _type + "; Datei: "+_xmlfile+"; Vaterknoten: "+_parent+"\n");
		if(_childNodes.size()>0){
		for(int i = 0; i< _childNodes.size(); i++){
			_childNodes.get(i).printNode();
		}
		}
	}

}

Könnte so etwas funktionieren? Und wenn ja, dann muss ich doch für die Typen eigene Klassen schreiben, also Artikel, Dokument und Datei. Wäre für einen Rat dankbar 🙂
 
da DOM für die vorraussichtliche Menge an Daten zu langsam ist.

Ich bin immer wieder überrascht, wie wenig Ahnung man benötigt um so eine Aussage treffen zu können.

Dein Problem scheint nicht in der Verarbeitung des XML zu liegen, sondern in der Datenstruktur, die du zur Laufzeit benötigst. Dazu ist DOM tatsächlich ungeeignet.
Wenn alles in den Speicher passt, dann tut es bereits eine Hashmap und eine Klasse "Artikel". Vermutlich ist aber eine Datenbank besser geeignet, z.B. eine HSQLDB oder eine H2. Darauf kannst du dann auch besser Abfragen erstellen.
 
@FArt:

Diese Aussage habe ich getroffen, nachdem ich mich im Inet ein wenig über DOM, SAX und STAX informiert habe. Da Performance in meinem Fall wichtig ist, habe ich mich für STAX entschieden.
Die Idee eine Datenbank zu bauen ist an und für sich durchaus richtig, die XML-Datein stammen nämlich aus einer ORACLE-DB, jedoch soll das Programm nunmal mit den XMLs leben, die man ihm vorsetzt.

Richtig ist, dass ich ein Problem damit habe, eine solche Datenstruktur zu bauen, darum frage ich ja hier 🙂
 
Da Performance in meinem Fall wichtig ist, habe ich mich für STAX entschieden.
Die Frage ist: was heißt hier Performance. Deine Anforderungen lassen kein Problem im Handling mit DOM erkennen.

jedoch soll das Programm nunmal mit den XMLs leben, die man ihm vorsetzt.

Was heitß damit Leben? Dieses Programm hat keine Verbindung zur DB und erhält seine Daten aus XML. Ja und? Siehe mein Post von vorher, es ist immer noch gültig.

Sonst: präzisiere dein Problem, am besten mit sinnvollen Aussagen. "Mit XML leben" oder "ich benötige Performance" habe ich ein wenig Verständnisprobleme was du hier erwartest.
Warum ein Baum? Alles im Speicher (sicher?)? Was spricht gegen eine Map und Artikelobjekte? Vielleicht eine TreeMap? Was hat das mit XML zu tun, wenn das Zeug schon geparst ist?
 
Zuletzt bearbeitet:
1. Performance heißt in meinem Fall, dass 50.000 Dateien oder mehr geparst werden müssen. Dabei sollen die Zusammenhänge dieser Dateien gespeichert werden. Diesem Beziehungswirrwarr soll dann eine Datei geschrieben werden, aus der dann hervorgeht, wie welcher Knoten mit welchem Knoten zusammen hängt, und das ganze eben as fast as possible.

2. Präzision:
Ich möchte die XML Dateien mit StAX parsen und dabei pro Datei einen "Knoten" vom Typ Artikel, Dokument, oder Datei erstellen. Ein Knoten kann beliebig viele Kinder von beliebigen Typ besitzen.

Wie muss die Datenstruktur dafür aussehen? Eine generische Klasse Node<T>? Oder eine Klasse für jeden Typ? Sprich ArticleNode, DocumentNode, FileNode welche von einer abstrakten Klasse Node abgeleitet werden? Kann eine generische Klasse überhaupt Objekte aufnehmen oder nur primitive Datentypen?

Noch präzieser kann ich's nicht formulieren, ich hoffe das reicht.
 
Zuletzt bearbeitet:
1. Performance heißt in meinem Fall, dass 50.000 Dateien oder mehr geparst werden müssen. Dabei sollen die Zusammenhänge dieser Dateien gespeichert werden. Diesem Beziehungswirrwarr soll dann eine Datei geschrieben werden, aus der dann hervorgeht, wie welcher Knoten mit welchem Knoten zusammen hängt, und das ganze eben as fast as possible.

2. Präzision:
Ich möchte die XML Dateien mit StAX parsen und dabei pro Datei einen "Knoten" vom Typ Artikel, Dokument, oder Datei erstellen. Ein Knoten kann beliebig viele Kinder von beliebigen Typ besitzen.

Wie muss die Datenstruktur dafür aussehen? Eine generische Klasse Node<T>? Oder eine Klasse für jeden Typ? Sprich ArticleNode, DocumentNode, FileNode welche von einer abstrakten Klasse Node abgeleitet werden? Kann eine generische Klasse überhaupt Objekte aufnehmen oder nur primitive Datentypen?

Noch präzieser kann ich's nicht formulieren, ich hoffe das reicht.

Es gilt immer noch meine Aussage aus dem ersten Posting. Sinnvoll ist es nicht alle Daten im Speicher zu halten und zu verknüpfen, sondern in eine DB zu lesen, aus der die Zusammenhänge der Daten natürlich hervorgehen.

1. Schritt
XML lesen (und parsen): trivial
2. Schritt
Daten in DB eintragen
3. Schritt
Daten aus DB auslesen
4. Schritt
neue XML Daten schreiben (auch trivial)

Wenn man es klug macht, dann liest man die Dateien einzeln und trägt sie in die DB. Evtl. müssen noch zusätzliche Daten geschrieben werden, die die Zusammenhänge zwischen den Datensätzen herstellen bzw. für eine spätere Auswertung optimieren.
Das Schreiben der Ausgabedatei macht man am besten auch nicht am Stück sondern immer als Batch für z.B. 100 Artikel.

Wie gesagt, spricht immer noch nichts gegen DOM, aber die Wahl der XML Api ist hier absolute Nebensache, wie eigentlich die gesamte XML Verareitung hier nicht das Problem darstellt.

Wenn du mit einer dicken Datenstruktur im Speicher arbeiten möchtest, dann kümmer dich erst mal um die Darstellung der Daten (Klasse Artikel). Danach kommt es darauf an wie sich die Zusammenhänge darstellen, denn daraufhin musst du die Datanstruktur optimieren. Dazu kannst du einen Baum verwenden. Fertige Implementierungen gibt es wie Sand am Meer, du musst aber wissen welche Art Baum für deine Daten optimal ist.
 
Deine DB Lösung in allen Ehren, aber ich kann nicht davon ausgehen, dass die Rechner, auf denen das Programm später laufen wird, über eine DB verfügen. Das Programm wird, wenn es fertig ist, auf verschiedene Client-Rechner verteilt, auf denen verschiedene XMLs liegen. Ich habe also die Vorgabe ohne DB auskommen zu müssen. Da bleibt nur der Speicher, auch wenn es dir nicht sinnvoll erscheint.

@maki: Danke für den Tip mit den Pattern.
 
Wenn Du komplett mit dem impliziten Baum aus der Datenbank arbeiten willst, dann bringt Dir Einlesen über DOM nicht mehr viel.
Wenn Du den Baum nicht behältst, dann brauchst Du ihn gar nicht erst aufbauen. In dem Fall schieb die Daten einfach Eintrag für Eintrag rüber, den Rest macht die Datenbank.

Was mich an der Sache zusätzlich etwas irritiert:
Du sprichst von einem Baum, aber gleichzeitig von Zuordnungen zwischen den einzelnen Elementen. Wenn es bei den Daten Relationen (Querverweise) gibt, dann ist es effektiv kein Baum mehr, sondern nur noch ein Graph.
Und dann bietet sich die Datenbank noch viel mehr an.
 
Zuletzt bearbeitet:
Deine DB Lösung in allen Ehren, aber ich kann nicht davon ausgehen, dass die Rechner, auf denen das Programm später laufen wird, über eine DB verfügen. Das Programm wird, wenn es fertig ist, auf verschiedene Client-Rechner verteilt, auf denen verschiedene XMLs liegen. Ich habe also die Vorgabe ohne DB auskommen zu müssen. Da bleibt nur der Speicher, auch wenn es dir nicht sinnvoll erscheint.

@maki: Danke für den Tip mit den Pattern.

Deswegen meine Hinweise auf HSQLDB oder H2, die man auch embedded betreiben könnte. Die DB wird nur temporär und zur Laufzeit aufgebaut.
 
Zuletzt bearbeitet:

Zurück
Oben