# XML mit Java auslesen (DB im Hinterkopf)



## aja (4. September 2007)

Hallo,
ich möchte ein .xml-Dokument mittels Java auslesen. Mein ganzes Projekt soll eine Webapplikation sein und die ersten Schritte in Struts sind auch schon gemacht. Nun gehts an die eigentliche Arbeit und bevor ich loslege, möchte ich gerne Eure Meinung wissen
Es wird nämlich eine xml-Datei ausgelesen, in der "Datenbank-ähnliche" Daten stehen, sprich: verschiedene Tabellen mit bestimmten Attributen, die auch teilweise mit Werten vorbelegt sind. Am Ende soll es möglich sein, die Attributwerte zu bearbeiten. Sehe ich das richtig, dass ich dann lieber DOM benutzen soll, damit ich die einzelnen Knotenelemente ansprechen kann? Wie kann ich die ganzen Elemente abspeichern, damit ich auf die Einzelnen zugreifen kann? Muss ich die in den Sessions in meiner Webapp immer weiterschleppen? Wie macht man es "günstig"? (Die Dateien, um die es sich handelt werden ca. 2000er Zeiler sein)
Später soll die Anwendung noch so erweitert werden, dass man auch direkt auf eine DB zugreifen kann, dort die Attributwerte auslesen und bearbeiten können. Es wäre also mehr als wünschenswert wenn die Zwischenschritte für die beiden Fälle anwendbar wären.
Und noch eins: wie realisieren ich in Java eine Navigation? Ich meine, die Datei, die bearbeitet wird, ist an einem festen Ort abgespeichert. Aber wenn man eine Datei aus einer anderen Quelle bearbeiten möchte, müsste man den Pfad irgendwie eingeben können. Wie macht man so ein "Durchsuchen..."?
Wäre für jeden Vorschlag sehr dankbar, da ich ein richtiger Neuling auf dem Gebiet bin...

Schöne Grüße,
aja


----------



## zerix (4. September 2007)

Nochmal Hallo, 

ich würde dir empfehlen das Data Access Object (DAO) mal anzuschauen. Das ist gut geeignet, wenn man die PersistenceSchicht ändern will (z. b. XML -> Datenbank).

http://www.tutorials.de/forum/java/285260-data-access-object-java.html

So einen "Durchsuchen"-Dialog gibt es bei Java schon fertig. Nennt sich JFileChooser.

MFG

zEriX


----------



## Thomas Darimont (4. September 2007)

Hallo,



> So einen "Durchsuchen"-Dialog gibt es bei Java schon fertig. Nennt sich JFileChooser.


... dann bau du mal einen JFileChooser in ein WEBANWENDUNG ein...

Bei einer Webanwendung benutzt man i. d. R. den File Selection Dialog des Browsers / Betriebsystems via entsprechendem HTML Formular:

<INPUT TYPE='file' NAME='filename'>
<INPUT TYPE='submit' VALUE='upload'>

Also zum Mappen der XML Daten auf Java Objekte bieten sich verschiedene XML DataBinding Frameworks an:
JAXB
XMLBeans
Castor
JBind
JBiX
...

Gruß Tom


----------



## zerix (4. September 2007)

Thomas Darimont hat gesagt.:
			
		

> ... dann bau du mal einen JFileChooser in ein WEBANWENDUNG ein...


Ups, das hab ich ja ganz vernachlässigt. 

MFG

zEriX


----------



## aja (4. September 2007)

Hi Jungs, danke für die Hinweise, aber... ich bin jetzt total durcheinander. Als Allererstes habe ich mich etwas über die DAOs schlau gemacht und so wie ich es verstanden habe, ist es möglich mit deren Hilfe  z.B. eine neue Tabelle in einer DB anzulegen. Ich bin aber mehr interessiert in den Schritten, die davor passieren. Erstmal nur mit der .xml-Datei. Ich wüsste nicht so wirklich wie ich da die DAOs einsetzen kann.  In dem Beispiel von zerix (in dem verlinkten Thread) sieht das Business-Objekt eigentlich wie eine Bean aus... (Oder lege ich da total daneben?) 
Es macht es irgendwie schwieriger für mich, dass meine Objekte aus einer Datei eingelesen und nicht fest vordefiniert werden... Wenn ich zu den nicht ganz verständlichen DAOs noch die zahlreichen von Thomas vorgeschlagenen Frameworks draufpacke, bin ich verloren  Könnte mir einer von Euch vielleicht einen Punkt zeigen, an dem ich "festklammern" kann?

Auch dies mit dem HTML-Formular ist mir leider unklar. Ich setze Struts ein. An welcher Stelle (bzw. in welcher Komponente) kann ich es am besten unterbringen (nicht jsps, oder?)

Danke für jegliche Hilfe,
aja


----------



## zerix (4. September 2007)

DAOs sind grob gesagt dafür da, dass man den Code wie man was speichert aus dem anderen Code raushält.
Mit dem Interface definierst du welche Methode es gibt, und in der Implementation sagst du dann wie es gespeichert wird. Das kann eine Datenbank sein, das kann eine XML-Datei sein.  Das ist vollkommen egal, solange die Methoden den Zweck erfüllen für den sie da sind. So kannst du nachher ohne größere Umstände von einer XML-Datei auf eine Datenbank umsteigen oder kannst auch beides ganz leicht gleichzeitig benutzen.

Das Business-Object ist eine Bean. Ich kenne dein Projekt nicht, aber ich würde dir emfehlen, dass du dir auch eine oder mehrere Beans machst. 


> Es macht es irgendwie schwieriger für mich, dass meine Objekte aus einer Datei eingelesen und nicht fest vordefiniert werden...


Was meinst du damit? Meinst du mit Datei die XML-Datei? Falls ja, dann kannst du dir doch eine Bean machen. Du ließt die Daten aus der Datei ein und befüllst die Bean und dann gibst du einfach das befüllte Object zurück.

Die Frameworks die Thomas gepostet hat sind Frameworks die eigentlich nichts anderes machen, als aus Daten die in einer XML-Datei stehen Java-Objecte zu machen, bzw Java-Objecte in einer XML-Datei zu speichern.


MFG

zEriX


----------



## aja (4. September 2007)

Ja, mit der Datei war meine .xml-Datei gemeint. Ich würde das jetzt so machen, dass ich mir eine Bean erzeuge, in der ich die  Elemente einlese (wahrscheinlich mit JDOM) und dann würde ich den Content weitergeben. Bin mir aber nicht sicher, an welcher Stelle ich die DAOs  mitspielen lassen sollte... Vielleicht versuche ich zu erklären, wie ich es verstanden habe, damit ihr mich korrigieren könnt...
Also ich würde (eine) Bean haben, in der alle von der xml-Datei ausgelesene Elemente drinne stehen. Es ist sehr praktisch, da in dem direkt drauffolgenden Schritt soll sich der Benutzer aussuchen können, was er als nächstes macht und so müssen die Daten nicht immer mitgeschleppt werden. 
Dann würde ich - ähnlich wie in dem Beispiel von zerix ein Interface implementieren, wo die gewünschten Änderungsoperationen vordefiniert werden. Danach eine Klasse, die das Interface implementiert und konkrete Methoden fürs Ändern usw. hat...
Ich werde bestimmt noch massenweise Probleme bei der Struts-Umsetzung haben aber trotzdem vielen Dank für Eure bisherige Hilfe 

Gruß,
aja


----------



## zerix (4. September 2007)

Das mit dem DAO ist nicht so schwer. In dem Link den ich gepostet hab, findest du auch ein generisches Interface von Thomas. Das stellt Methoden für die grundlegendsten Funktionen zur Verfügung.
In meinem Beispiel siehst du das Interface(EmpDAO) und eine Klasse dazu(EmpDAOImpl). Die Implementation ist das eigentliche DAO. Da schreibst du wie du das Object abspeicherst, updatest, ausliest, usw. Du könntest mein Beispiel einfach auf XML umstellen, in dem du einfach die EmpDAOImpl-Klasse neu implementierst und darin alles in eine XML-Datei schreibst, bzw aus einer XML-Datei ausliest.
Also der ganze Zugriff auf die Datensätze aus der Datei erfolgt ausschließlich über diese Klasse.

MFG

zEriX


----------



## aja (5. September 2007)

Danke, zerix.
Ich dachte, ich mache das so, dass ich in der Bean den Zugriff auf die xml-Datei habe damit ich die allen Parameter setzen kann. Ich würde gerne eine ähnliche Implementierung wie deine machen, aber... Ich müsste am besten auf Tupel arbeiten und sie sind von Tabelle zu Tabelle unterschiedlich. Wie kann ich da einen Typ draus machen? 

Um es genauer zu sagen: es gibt in der Datei *table*-Tags, die unteschiedliche Namen haben und dann sind noch die Spaltenattribute definiert mit bestimmten Namen und Werten für jedes Tupel, siehe hier:

```
<table name="Location">
    <initial-data>
        <row-content>
              <column-data columnName="Id" value="0"/>
              <column-data columnName="Name" value="Default"/>
              <column-data columnName="UUID"    
                                   value="00000000-0000-0000-0000-000000000000"/>
              <column-data columnName="Description" value="The default location"/>
        </row-content>
        <row-content>
         .......
    </initial-data>
</table>
```

Es wäre also sinnvoll "row-content" als Typ zu haben, aber der ist bei allen Tabellen unterschiedlich. Wie könnte ich sowas lösen?

Und noch eins: wo bekommt meine Bean die Daten her? 

Gruß,
aja


----------



## zerix (5. September 2007)

Die Daten hängen doch bestimmt irgendwie zusammen. Und so stellst du dir auch die Bean zusammen. Zum Beispiel könntest du - wie du schon meintest - aus einem Row-Content eine Bean machen. Das ist auch richtig so. Die Bean repräsentiert eine Zeile aus der Tabelle.

Wenn Du halt mehrere "Tabellen" hast, musst du halt auch mehrere Beans definieren.



			
				aja hat gesagt.:
			
		

> Und noch eins: wo bekommt meine Bean die Daten her?


Das musst du halt machen. Entweder mit SAX, DOM oder StaX auslesen, ein neues Object der passenden Bean erstellen. Das Object mit Daten befüllen und zurück geben.

Der andere Weg wäre, wenn du dir eins der Frameworks anschaust die Tom gepostet hat. Da musst du dich nicht mehr drum kümmern wie die Daten in deine Bean kommen. 

MFG

zEriX


----------



## aja (5. September 2007)

Ok, dann schaue ich mir erstmal die Frameworks an - wird so wahrscheinlich einfacher...
Ich lese also die Daten (mit Hilfe von FW) aus und dann übergebe ich die einzelnen Parameter den Beans? Oder greifen Beans auf die FW zu? Nee, kann nicht sein, oder? Denn so wie ich Euch verstanden habe, muss es danach auch möglich sein, die "Zeilen" mit DB-Werten zu futtern. Stimmt's?

Gruß,
aja


----------



## zerix (5. September 2007)

Solche Frameworks konfigurierst du meistens über eine XMl-Datei. Dann können diese Frameworks dir die Objecte zusammen bauen. Du musst dich darum nicht mehr kümmern. 
Ich hab bei meinem Beispiel ja Toplink verwendet, das ist ein solcher Mapper für Datenbanken. wie du siehst brauche ich da meine Bean nicht mehr zu befüllen, sondern es wird mir direkt ein Object zurückgegeben.


```
public Employee findByPriKey(Long key) throws DaoException {

        ReadObjectQuery query = new ReadObjectQuery(Employee.class);

        query.setSelectionCriteria(new ExpressionBuilder().get("empno").equal(

                key));

        Employee emp = (Employee) clientSession.executeQuery(query);

        UnitOfWork uow = clientSession.acquireUnitOfWork();

        uow.registerObject(emp);

        uow.release();
        return emp;
    }
```


```
Employee emp = (Employee) clientSession.executeQuery(query);
```
Employee ist hier meine Bean. Wie du siehst befülle ich die Bean nicht, sondenr ich bekomme direkt eine Instance zurück.
Das machen solche Frameworks für dich. Wenn du nicht so ein Framework benutzt, musst du halt selbst ein Object anlegen und es befüllen und zurück geben.

MFG

zEriX


----------



## aja (5. September 2007)

Ok, also ich habe gerade erfahren, dass ich keine zusätzlichen Frameworks benutzen soll  Ich muss es also alles per Hand machen... Ich verstehe dein Beispiel, bin mir aber immernoch nicht ganz sicher wie ich es machen kann. Angenommen ich fange mit der Tabelle an, deren Code ich hier gepostet habe (Location). Dazu mache ich eine LocationBean, die vorgibt, dass eine Location aus Id, Namen, usw. besteht. Aber wo lese ich die .xml-Datei ein? Wenn ich es in der Dao-Implementierung mache, dann entsteht doch ein Misch-Masch aus den Werten aller möglichen Tabellen, oder? Muss ich etwa in jeder Bean auf die .xml-Datei zugreifen und der Bean sagen, dass sie nach einer Tabelle mit dem bestimmten  Namen suchen soll und dann die Attributwerte zu den vorgegebenen Attributen der Tabelle auslesen?

Gruß,
aja


----------



## zerix (5. September 2007)

Du greifst in dem DAO auf die XML-Datei zu. Du musst natürlich für jede Bean auch ein eigenes DAO implementieren. So gibt es dann kein MischMasch, sondern jedes DAO ist für eine XML zuständig.

MFG

zEriX


----------



## aja (5. September 2007)

Naja, es ist nur eine xml-Datei, in der aber mehrere Tabellen definiert sind. Soll dann die ganze Datei mit einem Dao eingelesen werden? Woher wissen dann die Beans, welche Tupeln zu welcher Bean gehören? Und noch was: liest das Dao die ganze Datei in den Speicher ein (ich soll DOM benutzen) oder nur die Werte/die Struktur? Lege ich in den Beans die Tabellennamen und -attribute fest oder werden die auch irgendwie eingelesen?

Gruß,
aja


----------



## zerix (5. September 2007)

Wenn du DOM benutzen sollst, musst du ja einen DOM-Baum aufbauen, also die Datei in den Speicher lesen. In einem solchen DOM-Baum kannst du wirklcih alles abfragen, was die XML-Datei betrifft. In den Methoden die das DAO-Interface vorgibt befüllst du dann die Beanobjecte.

Grob gesagt, angenommen du suchst eine Location anhand der ID. Also nutzt du die Methode des DAOs findByPrimaryKey(int id) (Die Methode muss nicht zwingend so heißen, sollte aber vorhanden sein). In der Methode läufst du durch die Unterelemente der Location-Tabelle in deinem DOM-Baum,  und wenn du die Id gefunden hast. Legst du dir ein neues Object von deiner Bean an, befüllst dieses Object mit den Werten aus dem Baum und gibst das Object zurück.

MFG

zEriX


----------



## aja (5. September 2007)

Danke, zerix.
Ich habe nun angefangen, die Beans zu konstruieren. Ist es echt so einfach:

```
public class LocationBean implements Serializable {

	private static final long UUID = 00000000-0000-0000-0000-000000000000;
	private int id = 0;
	private String name = null;
	private String description = null;
	
	public LocationBean(){
	}
	
	public LocationBean (int id, String name, String description){
		this.id = id;
		this.name = name;
		this.description = description;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
        ...... (weitere Getter/Setter, für UUID nur Getter)
```
 ?

Was das weitere Vorgehen betrifft... Den DOM-Baum kann ich erzeugen, aber...
In meiner Applikation wird das so, dass man die einzelnen ganzen Tabellen einlesen kann und dann den(die) Zeilenwert(e) ändern, und nicht die konkreten Attribute anspricht. Um bei dem Location-Beispiel zu bleiben:

könnte ich z.B. eine Methode _getLocationTable()_ im DAO definieren? Wie könnte man sie dann implementieren? Müsste man in dem Baum nach einer Tabelle mit dem Namen "Location" suchen und die Werte der Unterknoten holen?

Wenn ich richtig liege, wie gibt man die Werte zu der Bean und die Bean zurück?
Würde es in etwa so ausschauen:

```
die Tabelle Location - weiß nicht wie - finden
...LocationBean location = new LocationBean();
in der Schleife die Unterknoten durchgehen
```
Man, ich weiß echt nicht weiter  Wie kann ich mehrere Zeilen an die LocationBean anhängen? Wie gib ich die Bean befüllt zurück?

Du lachst dich bestimmt kaputt, zerix Aber ich möchte es echt lernen und habe kein Plan. Vielen Dank für deine bisherigen Aufklärungen - sie helfen mir sehr weiter

Gruß,
aja


----------



## zerix (5. September 2007)

Warum hast du die uuid static gemacht?

MFG

zEriX


----------



## aja (5. September 2007)

Weil ich gesehen habe, dass die sich in 4 Dateien nicht ändert. Ok, war blöd.
Und der Rest?

Gruß,
aja


----------



## aja (5. September 2007)

Kann ich auch irgendwie sicher stellen, dass manche Attribute in einer Tabelle nicht 2mal denselben Wert haben dürfen? (PKs) Und wie siehts mit Abhängigkeiten aus? (FKs)

Gruß,
aja


----------



## zerix (5. September 2007)

Na das lässt sich alles umsetzen, aber du musst es halt selbst schreiben.

Da du keine anderen Frameworks nutzen darfst, musst du alles selbst umsetzen.

Das mit dem PK ist nicht so schwer. Du machst einen Zähler den du immer abspeicherst. also entweder in die gleiche Datei oder in eine andere. Wenn du einen PK brauchst, liest du die Zahl aus, zählst sie eins hoch. Diese Zahl kannst du dann benutzen und dann schreibst du sie wieder zurück. Wenn du dann nochmal einen neuen Key brauchst machst du das ganze nochmal. 
Bei einer DB wird das mit einer Sequence-Tabelle gemacht.

MFG

zEriX


----------



## aja (6. September 2007)

[edited]
Danke für die Antwort zerix. Aber die Bean , die ich gepostet habe... Geht das schon in die richtige Richtung?


----------



## zerix (6. September 2007)

Sag mal, kann es sein, dass du dich im Forum vertan hast, oder in der Sprache?

MFG

zEriX


----------



## aja (6. September 2007)

Sorry für den Eintrag oben. Habs geändert. Aber die Bean... Sieht die schon so gut aus?
Sag mir bitte nur, wie ich an die Bean mehrere Zeilen ranhängen kann


----------



## aja (6. September 2007)

Bitte, hilf mir. Ich weiß echt nicht weiter.
Ich habe die Bean für Location wie oben gepostet.
Dann habe ich noch ein Interface, das mir die Methoden vorgibt, die auf den Daten ausgeführt werden sollen, also findAll, insert, update usw. Das Interface wird jeweils von einer konkreten Dao-Datei implementiert (z.B. LocationDao). Aber wie kriege ich die Daten darein? Muss ich jedes Mal, d.h. in jeder einzelnen Implementierung den DOM-Baum erzeugen? Wie kann man es anders machen?

Gruß,
aja


----------



## zerix (6. September 2007)

Wie du den DOM-Baum hälst bleibt dir überlassen. Vorteilhaft wäre es, wenn du den DOM-Baum irgendwo hälst, dass alle DAOs drauf zugreifen können. Zum Beispiel eine Klasse die die XML-Datei einließt und den DOM-Baum erstellt und auch wieder auf die Festplatte schreibt. Das ganze natürlich als Singleton implementiert.

Ein paar Gedanken solltest du dir schon selbst machen. Ich kann dir nicht alles vorsagen. Bisher hast du nämlich nur das Model und das Interface und dafür müsste man nicht sonderlich überlegen. Das ist nicht böse gemeint, aber wenn ich dir wirklich alles haarklein vorsagen muss, kann ich es dir auch selbst schreiben.

MFG

zEriX


----------



## aja (7. September 2007)

Ich weiß, es ist mir peinlich nach allem Möglichen zu fragen aber ...

Ich bin im 2.ten Semester Informatik, hatte vorher nie was mit Java am Hut und jetzt sitze ich im Praktikum und soll die Webanwendung schreiben, wovon ich keine Ahnung habe und wo mir keiner richtig weiterhelfen kann, weil sie alle in C schreiben und sich n dreck kümmern was ich mache. Ich muss es "nur" am Ende (sprich: am 18) fertig haben. Deswegen versuche ich so viel wie möglich dazu lesen, mache mir selbstverständlich Gedanken drüber, kann aber in der Kürze nicht z.B. alle Entwurfsmuster lernen  Und ohne die Grundlagen, die mir fehlen, ist es total schwierig überhaupt anzufangen... Ich dachte wenn ich erstmal son Schritt-für-Schritt mache, wird schon der Anfang gemacht.

Vielen Dank für deine bisherige Hilfe, zerix 

Gruß,
aja


----------



## zerix (7. September 2007)

Ein Großteil der Fragen die du hattest, hatten aber nichts mit dem DAO zu tun. Ich helf ja auch gerne, aber bei den Fragen die du stellst, macht es halt den Eindruck, dass du dir kaum selbst Gedanken machst. 
Ich hab selbst noch nicht Daten so aus einer XML-Datei gelesen, wie du es machen musst (XML-Datei als DB, ohne Framework auslesen). Also ich überlege mir auch wie man es lösen kann. Dabei versuch ich halt zu beachten, dass möglichst wenig Speicher genutzt wird. Zum Beispiel die XML-Datei nur einmal einlesen und für alle DAOs irgendwie zur Verfügung stellen, statt in jedem DAO die XML-Datei einzulesen.

Also du kannst ruhig weiter Fragen stellen, aber ich würde dann auch mal gerne Ergebnisse sehen. Bisher kam nämlich nur die Bean und das Interface, und das hättest du schon nach meinem ersten Post erstellen können.

MFG

zEriX


----------



## aja (7. September 2007)

Zerix, ich verstehe was du meinst. Ich hatte in meinem vorletzen Post auch gefragt, ob ich wirklich jedesmal auf die Datei zugreifen muss.... Leider kannte ich Singleton nicht, aber hinter meiner Frage stand auch der Gedanke: wie kann ich es einmal holen und allen anderen Objekten zur Verfügung stellen. Ich weiß in Java die grundlegenden Sachen halt nicht. Wüsste nicht, wie ich z.B. Werte von Objekten mitschleppe....

Ech, es wird ne hammerharte Woche.
Danke trotzem für den Anschub,
aja


----------



## zerix (7. September 2007)

Weißt du mittlerweile was das Singleton-Pattern ist und wie man es umsetzt?

Wie kommts eigentlich, dass du Java programmieren musst und alle anderen C? Wo du auch beim DAO drauf achten musst, wenn du es nachher einsetzt, dass du eine Factory nutzt um es zu instanzieren, sonst hast du nachher Probleme, wenn du die Implementation austauschen willst, weil du dann wesentlich mehr Klassen anpacken musst. So musst du nur die Factory anpacken. Noch besser wäre es, wenn du es über dependency injection machen könntest, dann bräuchtest du deine Klassen gar nicht mehr anzupacken. Aber das ist erstmal nebensache.

Wie weit bist du denn jetzt?

MFG


zEriX

PS: Ich hab gar nicht studiert. Programmieren generell seit 2, 5 Jahren


----------



## aja (7. September 2007)

Ja, ich habe mich gestern ziemlich doll mit dem Singleton-Muster auseinander gesetzt und jetzt bin ich erstmal dabei, die Datei, auf dem Pattern basierend, einzulesen. Es war genau das, was mir gefehlt hatte und wo ich nicht so genau wusste, wie man es macht ohne jedes Mal die .xml-Datei einzulesen. Über Factory habe ich mich schon vorgestern etwas schlauer gemacht, weil der Begriff auch auf der von dir verlinkten Seite stand. 

Gruß,
aja


----------

