# Probleme mit XML und JTree



## Gelöschtes Mitglied 12486 (17. Mai 2009)

Hallo, ich versuche das was viele andere vor mir auch schon versucht haben. Ich möchte einen rudimentären XML Editor schreiben, welcher eine  XML Datei einlesen kann und diese in einem JTree darstellt. Als nächstes sollen die Elemente im JTree veränderbar sein, so dass ich dort was einfügen oder löschen kann. Nach dem ich damit fertig bin möchte ich das ganze natürlich auch wieder als neue .xml-Datei abspeichern können.

Mein Ansatz war, mir eine eigene Klasse MyTreeNode zu schreiben, welche dann die Interfaces TreeNode und Element implementiert. Damit wollte ich mir dann meinen eigenen Baum zusammen basteln. Mein Problem ist aber, dass TreeNode und Element ein paar gleichnamige Methoden haben und ich diese nun nicht ordentlich implementiert bekomme. Eine andere Variante war dann, einfach JDOM zu benutzen und dort von Element zu erben um das selbe zu erreichen. Dort gibt es aber wieder rum eine gleichnamige Methode die das ganze verhindert.

Ich steh nun ein wenig auf dem Schlauch, auch eine Forensuche hat mich immer nur bis zu dem Punkt gebracht, dass ich zwar eine .xml-Datei einlesen und im JTree darstellen kann, ich jedoch keinerlei Möglichkeit habe das dargestellte dann auch wieder in eine datei zu schreiben... jedenfalls fehlt mir da der Geistesblitz. Ich habe zwar immer wieder gelesen, die ginge mit JDOM, jedoch hab ich das entweder nicht gefunden oder nicht verstanden :/

Meine .xml-Dateien sehen wie folgt aus:

```
<start date="01.01.2001">
   <form size=1 title="example">
      <item size=1 type="String">
         <content>
            Hier steht der Content!
         </content>
      </item>
   </form>
</start>
```

Es gibt halt verschiedene Elemente mit verschiedenen Attributen. 


Kann mir da wer helfen? Gibts da nen klügeren Ansatz als das Zusammenführen der Funktionalitäten in eine Klasse? Oder versuche ich das Rad grad neu zu erfinden und es gibt bereits was passendes?


----------



## Wildcard (17. Mai 2009)

> Mein Ansatz war, mir eine eigene Klasse MyTreeNode zu schreiben, welche dann die Interfaces TreeNode und Element implementiert.


Ist in aller Regel unsgünstig Business Logik so eng mit der GUI zu koppeln. Warum zum Beispiel nicht so:
Deine TreeNodes *sind* keine XML Elements, sondern *haben* Elements.
Komposition/Aggregation ist der Vererbung häufig überlegen.


----------



## Gelöschtes Mitglied 12486 (17. Mai 2009)

Halli Hallo,

ich hab mir den Tip mal zu Herzen genommen und habe nun folgendes zusammengebastelt.


```
package test;

import javax.swing.tree.DefaultMutableTreeNode;
import org.jdom.Element;


public class XMLTreeNode extends DefaultMutableTreeNode {

    Element element;

    public XMLTreeNode(){
        super();
        element = null;
    }
    public XMLTreeNode(Element element){
        super();
        this.element = element;
    }

    public XMLTreeNode(Object userObject){
        super(userObject);
        element = null;
    }

    public XMLTreeNode(Object userObject, Element element) {
        super(userObject);
        this.element = element;
    }

    public XMLTreeNode(Object userObject, boolean allowsChildren, Element element) {
        super(userObject,allowsChildren);
        this.element = element;
    }

    public Element getElement(){
        return element;
    }
    public void setElement(Element element){
        this.element = element;
    }
}
```

Desweiteren hab ich nun folgende Methoden:

```
private static void buildTree(XMLTreeNode parent) {
        XMLTreeNode node = new XMLTreeNode();
        List<Element> elementList = parent.getElement().getChildren();
        for (Element element : elementList) {
            node.setElement(element);
            parent.add(node);
            buildTree(node);
        }
    }

    private static void traversTree(XMLTreeNode root){
        if(getParentNodeCount(root)<1)
            ausgabeln(root.getElement().getName()+": "+root.getElement().getTextTrim(),getParentNodeCount(root));
        Enumeration nodeList = root.children();
        while(nodeList.hasMoreElements()){
            XMLTreeNode node =(XMLTreeNode)nodeList.nextElement();
            if(node.getElement().getName().equals("content")){
                ausgabe(node.getElement().getName()+": "+node.getElement().getTextTrim(),getParentNodeCount(node));
            }else{
                ausgabe(node.getElement().getName()+": ",getParentNodeCount(node));
            }
            List<Attribute> attributeList = node.getElement().getAttributes();
            String s = "";
            for (Attribute attribute : attributeList) {
                s = s+attribute.getName()+"="+attribute.getValue()+" ";
            }
            ausgabeln(s,getParentNodeCount(node));
            traversTree(node);
        }
}
```

Diese setze ich wie folgt ein:


```
...
SAXBuilder builder = new SAXBuilder();
        try {
            Document doc = builder.build("c:/wisp/test.xml");
            XMLTreeNode rootNode = new XMLTreeNode(doc.getRootElement());
            tree = new JTree(rootNode);
            buildTree(rootNode);
            treeModel = (DefaultTreeModel) tree.getModel();
            tree.updateUI();
        } catch (JDOMException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
```

In meiner xml-datei steht folgendes:

```
<form title="Speiseplan 04.Mai-06.Mai" >
   <item type="string" title="Montag" >
      <content>04.05.</content>
   </item>
   <item type="string" title="Angebot:" >
      <content>Haehnchenbrust natur Paprikarahmsauce Blumenkohl Petersilienreis (G) (1,2,3,9)</content>
   </item>
   <item type="string" title="Alternative:" >
      <content>Kartoffel-Broccoli-Auflauf dazu Salat (V) (1,2)</content>
   </item>
   <item type="string" title="Dienstag" >
      <content>05.05.</content>
   </item>
   <item type="string" title="Angebot:" >
      <content>Frikadelle Braten Sauce Finger Moehren Kartoffelpueree (S)</content>
   </item>
   <item type="string" title="Alternative:" >
      <content>Asiatische Reispfanne dazu Salat (V)</content>
   </item>
   <item type="string" title="Mittwoch" >
      <content>06.05.</content>
   </item>
   <item type="string" title="Angebot:" >
      <content>Putenschnitzel paniert Pustasauce Salzkartoffeln gruener Mischsalat (G) (1,2,3,9)</content>
   </item>
   <item type="string" title="Alternative:" >
      <content>Erbseneintopf von gelben Erbsen mit Vegetarische Baellchen oder Putenbockwurst (V,G)</content>
</sForm>
```

Die Methode getParentNodeCount() gibt mir hier nur die Anzahl der Parents wieder, also in welcher Ebenen ich mich gerade befinde. Darüber rücke ich meine Ausgabe auf der Konsole ein, mit der ich teste was ich da so grade treibe. (Hier nun nicht so wichtig, aber die Datei ist eigentlich größer)

Mein Problem ist nun die traversTree(XMLTreeNode root) Methode. Diese soll ausgehend von einem Knoten die unterliegende Struktur der Datei zurück geben und auf der Konsole ausgeben. Leider funktioniert dies nicht richtig, es fallen jede Menge tags, welche in der xml datei drin stehen, raus. Die Ausgabe sieht dann z.B. so aus:

```
form:       title=Speiseplan 04.Mai-06.Mai
   item:         type=string title=Alternative: 
      content: 04.05.          
      content: Haehnchenbrust natur Paprikarahmsauce Blumenkohl Petersilienreis (G) (1,2,3,9)          
      content: Kartoffel-Broccoli-Auflauf dazu Salat (V) (1,2)          
      content: 05.05.          
      content: Frikadelle Braten Sauce Finger Moehren Kartoffelpueree (S)          
      content: Asiatische Reispfanne dazu Salat (V)          
      content: 06.05.          
      content: Putenschnitzel paniert Pustasauce Salzkartoffeln gruener Mischsalat (G) (1,2,3,9)          
      content: Erbseneintopf von gelben Erbsen mit Vegetarische Baellchen oder Putenbockwurst (V,G)
```

Das heisst, die <item>-Tags die eigentlich hier drin stehen sollten sind nicht mehr da. Ich hab leider keinen Ahnung wieso das so ist. Kann mir da jemand auf die Sprünge helfen?


----------



## Gelöschtes Mitglied 12486 (18. Mai 2009)

Hab meinen Fehler grade bemerkt... das funktioniert vorn und hinten nicht was ich da gemacht habe... Die komplette Baumstruktur kam aus einer anderen Methode... diese buildTree Methode funktioniert nicht wie gewollt. Ich hatte eine Klasse umbenannt und hatte aus Versehen ein Refactor gemacht und sie nicht bloß umbenannt... Daher wurde mein Code hier nie benutzt... und nun merk ich, dass er nicht funktioniert


----------



## Gelöschtes Mitglied 12486 (18. Mai 2009)

Nun habe ich zwar (glaube ich) eine Lösung für das ganze gefunden und ich bin der Meinung, dass sie funktionieren wird, jedoch funktioniert auf einmal etwas anderes nicht mehr.

Ich habe bisher den JTree auf einem sogenannten rootNode aufbauen lassen. Dieser ist ein Objekt meiner Klasse XMLTreeNode, welche ich dahingehend geändert habe, dass ich nun nicht mehr JDOM elemente mitgebe, sondern w3c.dom Nodes.

Soweit so gut, die XML file wurde geparsed und im Baum abgebildet. Nun habe ich einen JFileChooser eingebaut, mit welchem ich mir eine beliebige xml-Datei aussuchen kann. Übergebe ich diese Datei nun an den JTree, so ändere ich zwar erfolgreich das Model (durch Ausgaben heraus gefunden), jedoch aktualisiert sich die Ansicht nicht...

Ich habe nun alles ausprobiert... validate(), revalidate(), treeModel.reload(), treeModel.reload(mit parameter), treeModel.nodeChanged()... außerdem noch repaint(), tree.updateUI().

Nicht von alle dem bewegt meinen JTree dazu, die aktualisierten Daten anzuzeigen...

Hier mal mein Code:


```
public void loadFile(File file) {
   rootNode = makeRootNode(file);
   tree = new JTree(rootNode);
   treeModel = (DefaultTreeModel) tree.getModel();
   
   // alle Methoden zur Aktualisierung der UI hier angewendet

}
```

Die Methode loadFile wird wiederum vom FileChooser aufgerufen und bekommt die selektierte Datei übergeben. Die Methode makeRootNode(File file) erstellt mir einen XMLTreeNode aus einer xml Datei und ruft dann eine Methode auf, welche den Baum erstellt.

Was hab ich übersehen? Kann mir jemand hier helfen? Meinen Code zur Erstellung des Baums und alles weitere was der Editor machen soll kann ich nun nicht testen, da ich ja nicht in der Ansicht sehen kann was passiert...


----------



## Wildcard (18. Mai 2009)

```
tree = new JTree(rootNode);
```
Dir ist klar das du einen *neuen* Baum erzeugst anstatt den alten zu aktualisieren?


----------



## Gelöschtes Mitglied 12486 (19. Mai 2009)

Ja, das ist mir klar. Ich hab mich auch falsch ausgedrückt...

Ich hab sowohl den obigen Code versucht, in dem ich einen neuen Baum erzeuge und versucht habe den alten damit zu ersetzen. Ich habe aber auch folgendes probiert:


```
public void loadFile(File file) {
        rootNode = makeRootNode(file);
        treeModel.nodeChanged(rootNode);
        tree.setModel(treeModel);
        tree.updateUI();
   }
```

Dabei passiert auch leider gar nichts... entweder es passiert nichts oder mein Baum ist wieder mal nicht ordentlich aufgebaut worden, so dass er mit dem treeModel nichts anfangen kann...

So langsam blick ich nicht mehr durch


----------



## Gelöschtes Mitglied 12486 (19. Mai 2009)

Ich hab die Lösung nun gefunden. Die Methoden treeModel.reload(), treeModel.reload(mit parameter), treeModel.nodeChanged(), usw. machen alle was sie sollen. Das Model wird neu aufgebaut oder stukturiert. Und zwar immer vom Root aus. Nur hab ich gar nicht gemerkt, dass ich den Root im TreeModel nie neu gesetzt habe.

```
treeModel.setRoot(rootNode);
treeModel.reload(rootNode);
tree.setModel(treeModel);
tree.updateUI();
```

Diese Reihenfolge sorgt nun endlich dafür, dass im Model die Wurzel neu gesetzt wird, anhand dieser Wurzel ein neuer Baum im Model gespeichert wird und dieses Model dann im JTree angezeigt wird. Endlich hat meine Konfusion ein Ende.. war ja auch schwer genug 

Ein Problem hab ich nun aber noch, kann mir da jemand einen Tip zu geben?

Will ich eine XML Datei einladen, so erhalte ich folgende Fehlermeldung: 

```
Error making root node: com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 1 of 1-byte UTF-8 sequence.
com.sun.org.apache.xerces.internal.impl.io.MalformedByteSequenceException: Invalid byte 1 of 1-byte UTF-8 sequence.
        at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.invalidByte(UTF8Reader.java:674)
        at com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.read(UTF8Reader.java:547)
        at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.load(XMLEntityScanner.java:1742)
        at com.sun.org.apache.xerces.internal.impl.XMLEntityScanner.scanLiteral(XMLEntityScanner.java:1069)
        at com.sun.org.apache.xerces.internal.impl.XMLScanner.scanAttributeValue(XMLScanner.java:813)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanAttribute(XMLDocumentFragmentScannerImpl.java:1539)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanStartElement(XMLDocumentFragmentScannerImpl.java:1316)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:2747)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:648)
        at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:807)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
        at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:107)
        at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:225)
        at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:283)
        at javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:208)
        at xmltest.XMLTreePanel.makeNewRootNode(XMLTreePanel.java:77)
        at xmltest.XMLTreePanel.loadFile(XMLTreePanel.java:211)
        at xmltest.FunktionsPanel1.actionPerformed(FunktionsPanel1.java:62)
        at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
        at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
        at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
        at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
        at java.awt.Component.processMouseEvent(Component.java:6216)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3265)
        at java.awt.Component.processEvent(Component.java:5981)
        at java.awt.Container.processEvent(Container.java:2041)
        at java.awt.Component.dispatchEventImpl(Component.java:4583)
        at java.awt.Container.dispatchEventImpl(Container.java:2099)
        at java.awt.Component.dispatchEvent(Component.java:4413)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4556)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4220)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4150)
        at java.awt.Container.dispatchEventImpl(Container.java:2085)
        at java.awt.Component.dispatchEvent(Component.java:4413)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
```

Wie soll ich das verstehen? Ist die XML Datei in UTF-8 codiert und ich kann diese somit nicht öffnen? Wie kann ich verhindern, dass mir deswegen alles um die Ohren fliegt?


----------



## Wildcard (19. Mai 2009)

Da stehen irgendwelche falschen Zeichen drin. Evtl. ein byte order mark, oder die XML Datei lügt dich an in dem sie im Header angibt UTF-8 kodiert zu sein, dann aber doch anders kodiert.


----------



## Gelöschtes Mitglied 12486 (20. Mai 2009)

tatsächlich hat sie mich angelogen  Okay, danke für deinen kleinen Tips!


----------

