# XML Auslesen, wie abspeichern?



## Kababär (12. Apr 2016)

Hi Leute,

ich brauche einen Expertenrat von euch.
Ich habe eine circa 50MB große XML-Datei, die ich mit dem SAXParser einlese.
Mit System.out.println habe ich überprüft, ob auch alles gelesen wird - Bingo.
Nur weiß ich nicht, wie ich das ganze Konstrukt abspeichern soll, da die Hierarchie nicht ganz so trivial ist.
Ohne wirklich 1:1 die XML zu übertragen (darf ich nicht), will ich hier versuchen, die "Struktur" zu zeigen:

```
<Person_liste>
    <Person attribute: Vorname, Name, Alter>
        <zur_Person>
            <beruf>
                <beginn attribute: Datum />
                <fest_angestellt_seit attribute: Datum />
            </beruf>
            <hobbies_liste>
                <hobby attribute: Wo, seit, sportart, liga/>
                ...
            </hobbies_liste>
```
Dann alle Tags schließen, bzw bis zur Person. Denn es kann auch weitere Personen geben.
Ich habe mir überlegt, dass ich pro Tag quasi eine Klasse erstelle. Eine Klasse Personen, die eigentlich eine Liste repräsentiert, die eben Objekte der Klassen (Person, Beruf, Hoobies, ... ) hat. Oder die Klasse Person hat Klassenattribute, die eigentlich Objekte der Klassen sind. 
Aber irgendwie ist mir die Geschichte auf diese Art und Weise zu kompliziert. Wenn ich die Hobby-Liste ein Hobby hinzufügen möchte oder nur abfragen will, ob Person X im Ort S ein Hobby ausübt, wir die einfache Abfrage entweder ein hässlicher, schwerverständlicher 1-Zeiler und ich muss zudem für mein Empfinden zu tief dafür in das Objekt "eindringen".

Habt ihr elegantere Lösungen?


----------



## Kababär (12. Apr 2016)

Ich werde es nun vermutlich wie folgt machen:
Für Person_liste lege ich eine Klasse an. Diese speichert eine Liste von Personen.
Person ist wiederum eine Klasse mit den Klassenattributen Vorname, Name , Alter (Über Konstruktor setzen, mit getter Wert auslesen). Person zudem ein Klassenobjekt "zur_Person".
Zur_Person hat eine innere Klasse Beruf. Diese Klasse hat zwei Klassenattribute beginn und fest_angestellt_seit.
Zudem hat sie eine List<hoobies_liste> und eine Innere Klasse "Hobby", wo die Hobbies initialisiert werden und dann in die hobby_liste geschrieben wird.


----------



## mrBrown (12. Apr 2016)

Meint "abspeichern" das ganze irgendwie auf der Platte zu speichern, oder soll das nur intern irgendwie repräsentiert werden?

Falls letzteres, würde ich das ganze wie du selbst schon sagst Objektorientiert angehen und für jedes Klassen erstellen, für mich wäre das die eleganteste Lösung.

Hinzufügen ist doch nur sowas wie person.getHobbies().add(...), finden ob eins existiert für einen Ort etwa person.getHobbies().anyMatch(hobby->hobby.getOrt().equals(...)) (entweder mit eigener Liste oder nutzen von Streams). Zu hässlich und schwer verständlich finde ich das nicht.


Ansonsten je nach Bedarf wäre XQuery eine Idee, allerdings hab ich keine Idee wie das mit Java benutzbar ist.


----------



## Kababär (12. Apr 2016)

Von XQuery habe ich auch keine Ahnung.

Ich danke dir für deine Antwort. Dachte, dass meine bisherige Vorgehensweise zu kompliziert wäre, aber einfacher scheint es wohl wirklich nicht zu gehen. Jetzt muss ich nur noch die Objekte miteinander verknüpfen und dann steht soweit alles.

Danke dir nochmal.


----------



## Flown (12. Apr 2016)

In der JDK ist kein vollständiges XQuery vorhanden, aber XPath (ein Teil davon) schon. Genug Tutorials im Internet verfügbar.

Musst du jetzt die Daten speichern oder im Hauptspeicher halten?


----------



## Kababär (12. Apr 2016)

Sry, vergessen zu beantworten. Intern im Model speichern, also nichts auf der Festplatte.


----------



## Flown (12. Apr 2016)

Dann würde ich jedenfalls die Klassen erstellen und sogar JAXB verwenden. Dann musst du das un-/marshalling nicht selbst machen.


----------



## Kababär (12. Apr 2016)

Benötige ich dieses Marshalling? Ich meine die Attribute und deren Werte habe ich ja als String vorliegen. Diese können doch einfach abgespeichert werden in meiner Modelklasse und mit dieser Klasse kann ich doch arbeiten?


----------



## mrBrown (12. Apr 2016)

Du musst es doch aus der ursprünglichen XML-Datei laden und vermutlich auch wieder darin speichern?


----------



## Kababär (12. Apr 2016)

Nein die bearbeiteten Dateien werden nicht wieder in XML geschrieben


----------



## Flown (12. Apr 2016)

Marshalling ist das speichern von deiner Java Objektstruktur in die XML Präsentation. Wenn du nur lesen willst, dann brauchst du nur ein Unmarshalling. Egal wie, dass funktioniert dann automatisch und du brauchst dich nicht mit Stax/Dom/etc. herumzuschlagen und die Struktur selbst zu bilden. Wie schon gesagt, Tutorials gibt es zu hauf im Internet, auch für JAXB.


----------



## Flown (12. Apr 2016)

HIER hatte ich mal ein kleines Beispielprogramm für JAXB geschrieben. Hatte auch ein besseres, aber das finde ich auf die schnelle nicht (musst du eben selbst recherchieren)


----------



## Kababär (12. Apr 2016)

Hm das Unmarshalling habe ich schon fertig mit SAXParser, das Auslesen funktioniert auch super. Ich vermute mal er findet alles (habe mir jeweils StartTag und EndTag ausgeben lassen), nur mühsam zu überprüfen bei 50MB XML.
Und das sind nur 3 Methoden, insgesamt effektive 50 Zeilen Code.

Die Datenstruktur habe ich jetzt auch fertig für die Objekte. Nur kann ich die inneren Klassen nicht static machen, weil oftmals Objekte im Parameter vorhanden sind. Bspw. liefert getHobbies() ja eine List<Hobby>.
Beispiel:

```
Personen_liste personList = new Personen_liste();
personList.addPerson(personList.new Person("Max", "Mustermann", -1);
```

Ist unschön oder?
Das ließe sich beheben, wenn ich Personen_liste als Static deklariere und die inneren Klassen in der Toplevel-Klasse instanziiere?


----------



## Flown (12. Apr 2016)

Sowas händisch zu bauen ist doch der totale Overkill. Ich hab dir doch jetzt schon eine kleine Referenz gegeben, wie das automatisch alles funktioniert, dann musst du dich auch nicht damit herumschlagen.


----------



## Kababär (12. Apr 2016)

Ja JAXB ist wirklich relativ simpel und schnell. Ich würde auch lieber JAXB verwenden aber wir sind gezwungen das Rad neu zu erfinden.


----------



## mrBrown (12. Apr 2016)

Warum nutzt du überhaupt innere Klassen?
da irgendwelche Felder static machen wird eher neue Fehlerquelle sein...


----------



## Kababär (13. Apr 2016)

Schlägst du vor, für jedes Tag quasi eine neue Klasse zu schreiben?
Ich denke mit innere Klassen kriege ich die Hierarchie auch einfacher hin.

Das Static lasse ich weg, damit funktionier es nicht wie gewünscht, da keine Objekte erstellt werden können. Hätte icb aber auch gleich drauf kommen können.


----------



## mrBrown (13. Apr 2016)

Ich würde ganz normale Klassen erstellen, die Hierarchie erreicht man doch trotzdem?
Für mich kann rein logisch ein Hobby auch ohne Person existieren, und eine Person auch ohne PersonenListe...


----------



## Baldur (13. Apr 2016)

Gehts darum das möglichst speichersparend oder so hinzubekommen? (weil du ja schon SAX verwendest)

Vielleicht kann man ja auch eine Art Datenbank in Betracht ziehen. Leider keine Ahnung wie das bei Java ausschaut, ob es da auch was wie Sqlite gibt.
Sonst bleibt ja kaum was anderes übrig, als mehr oder weniger die XML-Struktur in Form von Klassen zu übernehmen, die werden sich aber auch entsprechend im Speicher breitmachen.


----------



## Kababär (13. Apr 2016)

Also Personenliste ist immer vorhanden. 
Auch wenn es keine oder nur eine Person gibt.

Leider steht dafür keine Datenbank zur Verfügung. Dass das ganze speicherplatzintensiv wird, habe ich mir schon gedacht, aber hier steht die Performance eher weniger im
Vordergrund. 

Ich denke ich habe aber jetzt die richtige Struktur gefunden, wie du sagtest wirklich immer eine .java Klasse schreiben. Dann geht das ändern des Codes schneller, falls sich mal ein Tag o.ä. Ändert.


----------



## dzim (13. Apr 2016)

Ich weiss nicht, ob JaxB die Antwort sein kann. Bedenkt: 50MB-XML muss erst mal in ein internes Format gebracht werden. So wahnsinnig performant und ressourcenschonend ist JaxB nicht. Finde die SAXParser-Variante eigentlich nicht schlecht. Oldskool, aber egal, wenn performant. Ich würde überlegen, wie du am besten die Struktur abbilden kannst. Machst du einen vollständigen Objekt-Baum, könnte es einiges an Ressourcen fressen. Vielleicht mit Maps (als Key den XML-Tag-Namen nutzen)?


----------



## Kababär (13. Apr 2016)

Genau das war anfangs auch mein Problem.
Zuerst hatte icb nur eine klasse, das war aber zu verstrickt. Dann habe ich mir überlegt einen Baum anzulegen, was die Performance aber unterirdisch machte, da es doch ganz schön viele Knoten gibt und die Breite fast quadratisch zunimmt pro Stufe.
Eine Hashmap hatte ich auch in Erwägung gezogen, doch als key hätte ich die Person. Als value den Rest (Adresse, Hobby, ... ). Oder ich könnte Person als key nehmen, die nächste Ebene als value nehmen, also bspw Adresse. Adresse aber auch wieder als key einer neuen Hashmap nehmen und Straße etc als value. Damit könnte die Struktur auch abgebildet werden.
Dazu müsste ich aber trotzdem die Klassen schreiben, nur die Beziehungen werden über die map dargestellt.
Glaube diese Lösung gefällt mir, auch wenn ich letztendlich zig Maps habe.
Dann prägt sich das auch mal ordentlich ein wie ich mit Maps umgehe 


Das einzige was mir nicht gefällt ist, dass mein Programm dann so XML-nah ist. Füge ich ein anderes XML ein, bspw eine Firma Struktur und Aufbau mit Leiter, Mitarbeiter, Produkte, Einnahmen etc, müsste ich wieder eine andere Datenstrukturen nehmen. 
Wenn ich es allgemeiner machen will, bräuchte ich Generische Klassen, oder?


----------



## dzim (13. Apr 2016)

Jep, das ist so. Aber auch wenn es mit JAXB etc sicher einfacher ist, Strukturänderungen vorzunehmen - machen musst du sie so oder so in jeder Variante.
Noch eine Idee hätte ich: Du kannst ja auch die Daten in eine in-memory-DB einlesen. SQLite, H2, HSQL - gibt sicher noch weitere Varianten... Da das Schema bei jedem auslesen dann neu erstellt wird, musst du die Strukturänderungen an den Tabellen (oder bei NoSQL auch den Dokumenten) und beim Einlesen berücksichtigen. Dieser Teil wird damit vielleicht nicht wahnsinnig viel weniger aufwendig, aber die Performance und der Memory-Footprint könnten relativ gering sein.
Aber das ist nur so eine fixe Idee, die mir gerade einfiel.


----------



## mrBrown (13. Apr 2016)

Was will man damit gewinnen, wenn man das ganze als Map darstellt?
Speichertechnisch dürfte der Unterschied minimal sein, du wirst ja sowieso jedes Element im Speicher halten. Ob Person eine Liste von Hobbys enthält, oder Person in einer Map der Key für eine Liste von Hobbys ist, spart ja keine Objekte ein.
Deine Struktur dürfte damit nur komplexer werden, höchstens der Zugriff auf bestimmte Elemente geht schneller, dafür bräuchtest du dann aber sinnvolle keys.

Eine In-Memory-DB könnte Sinnvoll sein, allerdings müsste man dann entweder direkt auf der DB arbeiten, oder trotzdem noch ein Model modellieren, also steht man wieder vor dem selben Problem.  50MB sind für mich auch noch nicht kritisch vom Speicherverbrauch her.

Wenn sich die Struktur des XMLs ändert, wird man sowieso alles anpassen müssen, generische Klassen dürften es da kaum leichter machen...


----------



## Kababär (13. Apr 2016)

Deine fixe Idee klingt ganz gut, nur sollen wirklich alle Daten innerhalb der Applikationen gespeichert und verarbeitet werden, das heißt keine externe DB oder ähnliches. 

Schade, dass generische Klassen da keine Abhilfe schaffen. Wobei das ja klar ist. Wenn die Tiefe eines XML Dokuments bezogen auf die Parent-Children Beziehung tiefer als die von mir strukturierte Klassenhierarchie ist, müssen neue Klassen her. Dynamisches erstellen von Klassen und deren Aufbau sowie die Definition dieser Klasse zu bereits bestehenden Klassen ist ja nicht möglich, geschweige denn dynamische Variablen erstellen (also mit Typ und Name). 

Denke dass eine Hashmap Trotzdem sinnvoll ist, weil die Objekte, die abgespeichert werden, in ihre Hashwerte zerlegt werden, oder? Dachte, dass die Objekte quasi komprimiert werden, was sich in der Größe (Speicherplatz) des Objektes auswirkt und bei Gebrauch wird dieses Objekt wieder entpackt. 
Die Objekte müssen trotzdem erstellt werden, aber sie werden dann gehasht abgespeichert?
Vielleicht habe ich das aber auch falsch verstanden. 

Na gut, das Thema kann als erledigt angesehen werden. 
Lösung: einzelne Klassen für jedes Tag anlegen und Beziehung über Zugriffsmöglichkeiten zwischen Klassen definieren. (Eventuell aber als HashMaps implementiert, die in einem seperaten Model gespeichert werden). 
Bei Änderung der XML Datei muss die Datenstrukturen angepasst bzw erweitert werden


----------



## mrBrown (13. Apr 2016)

Da hast du HashMaps falsch verstanden 
Das ist schon eine ganz normale Map, das Objekt wird ganz normal gespeichert und ist über den Key auffindbar. Das einzige was gehasht wird, ist der Key, und das nur zum schnelleren auffinden der Elemente, im Speicher liegt er trotzdem ganz normal. Speicher sparen kann man mit Hashs nicht, da sie nur ein eine Richtung funktionieren, aus dem Hash das Objekt wiederherstellen ist unmöglich.


----------



## dzim (13. Apr 2016)

Ich hätte, wenn dann überhaupt, eine reine Key-Value-Beziehung in der Map verwendet - keine Fancy-Objekte, denn sonst hast du schon recht, dann gewinnt man nichts.
Ich will auch nicht sagen, das 50MB auf die ein oder andere Art im Speicher ein Problem sind, das Problem ist nur der Prozess des einlesens. Der kann zum einen relativ lange dauern, zum anderen schlicht viel zusätzliche Speicher fressen. Kann man alles mit xmx und xms begegnen, ich meine ja nur 

Der Vorteil einer in-Memory-DB wäre die Zugriffsperformance (wenn das wichtig ist) und der geringe Speicherverbrauch (im wesentlichen nur das, was für die Daten eben notwendig ist - dürften in dem Fall weniger als die 50MB sein, da der XML-Tag-Overhead (+ evtl. viele Leerzeichen/Tabs zur Formatierung des Dokuments) entfällt). Es bleibt natürlich, dass du beim Auslesen der DB ein sinnvolles Model haben solltest, aber ich denke das ist auf jeden Fall resourcenschonender. Aber vielleicht auch Overkill hier in diesem Scenario. Mir egal: Ich hab ne Idee geliefert, was daraus gemacht wird ist dem TO überlassen


----------



## Kababär (22. Apr 2016)

Ok Leute, alles nochmal auf Anfang. 
Nachdem kläglich versucht wurde, eine reine Objektstruktur zu bilden und dies dann doch bis zu 2000 Zeilen lang wurde alleine für die Struktur und Beziehungen, wurde JAXB doch erlaubt. 
Allerdings blicke ich da nicht so ganz durch. 
Ab Java SE 6 ist JAXB standardmäßig dabei im JDK? 
Und die Klassen für das Mapping kann ich mir generieren lassen aus der XML und der XSD Datei? (eine XSD kann ich mir mit JAXB generieren lassen?)

Das unmarshall wäre ja nur ein paar Zeilen Code. Aber ich bin seelisch am Ende mittlerweile, weil das zusammenbasteln meine Nerven gekostet hat


----------



## dzim (22. Apr 2016)

JaxB ist seit ewig und drei Tagen dabei. MAch dir da also keine Sorgen. Du musst aus dem XML ein XSD generieren (nein, dass kann JaxB IMHO nicht). Nachdem du das XSD überprüft/überarbeitet hast (wenn du XML als Ausgangspunkt nimmt, weiss es natürlich nicht unbedingt etwas von optionalen Attributen und Elementen), kannst du aus dem XSD mit dem Programm "xjc", das Teil des JDK ist, dir die für JaxB notwendigen Modell-Klassen generieren lassen.


----------



## Kababär (22. Apr 2016)

Ohwei, mit XML hatte ich leider noch gar nichts am hut obwohl ich Informatik studiere. Verrückt, oder? 
Na gut dann werde ich mir mal XSD angucken (eigentlich seltsam, dass es hierfür keine offiziellen Converter-Lösungen gibt) und dementsprechend xjc. 

Aber eine Frage, da ich gerade unterwegs bin und ich bisschen reden möchte:
Kann ich xjc in der cmd laufen lassen oder muss das tatsächlich codiert werden? Könnte ja sein, dass ein Converter Befehl a LA "-xjc pathToXML -XSD" oder so gibt


----------



## dzim (22. Apr 2016)

Erste Frage: Was für eine IDE nutzt du? Eclipse unterstützt, wenn ich mich recht entsinne, bei korrekter Plugin-Wahl ein konvertieren von XML nach XSD. Es gibt aber auch Web-Tools, mit denen du das machen kannst.
Ich habe mir seinerzeit XSD via "Learning by doing" beigebracht. Mein Studium konnte mir lediglich mit Ideen geben, wo ich suchen muss (später bei Themen wie XPath, XQuery und XSLT).

Hier etwas Doku zum Lesen:

Google: "xml to xsd" -> http://www.freeformatter.com/xsd-generator.html - http://xmlgrid.net/xml2xsd.html - .........

XML Schema (XSD):
- https://de.wikipedia.org/wiki/XML_Schema (Wikipedia hilft fast immer , auch mal die englishe Seite dazu lesen!)
- http://www.w3schools.com/xml/schema_intro.asp (w3schools ist für viele Web-Sachen eine gute Quelle für schnelle Hilfe, wenn auch nicht immer feingranular genug)
- https://www.w3.org/XML/Schema (w3.org - offizieller geht es nicht - das ist die ermüdende Spezifikation, wenn du mal nichts besseres am WE vor hast: viel Spass damit!)

XJC bei Oracle: https://docs.oracle.com/javase/8/docs/technotes/tools/unix/xjc.html
Ein Blog mit Beispielen zu XJC : http://www.thoughts-on-java.org/generate-your-jaxb-classes-in-second/


----------



## Kababär (22. Apr 2016)

Oh danke bisschen Literatur für die Zugfahrt! 
Ich melde mich wenn es an die JAXB Programmierung geht und ich über Steine stolpere.

PS: ich bin von Eclipse zu NetBeans umgestiegen


----------



## Kababär (22. Apr 2016)

Habs hinbekommen. Zuerst mittels einem Online Formatter zu einem .xsd geparst und mit xjc die Klassen erstellt. Lustigerweise hat xjc mit der Online Formatter erstellten .xsd-Datei besser gearbeitet als mit der von Visual Studio 2015 erstellen .xsd.

Lustig: Mein eigener Code für die Struktur, einlesen, Beziehungen bilden, etc. hat knapp 30 Sekunden gebraucht. JaxB braucht nur 1-2 Sekunden


----------

