# XML verändern



## ForenDaddy (13. Apr 2011)

ich weiss, das thema gibt es hier schon.
aber es lässt sich für mich irgendwie nicht lösen.

ich möchte eine xml datei erstellen, die bestimmte flags halten soll.
ich übergebe eine Auftragsnummer und das objekt flag, momentan nur gefüllt mit einer variablen "abgeschlossen" die den inhalt 0 oder 1 haben kann.

*Funktionen:*
(1) Wenn die flag datei nicht existiert, erstelle eine neue mit dem notwendigen inhalt (FUNKTIONIERT)
(2) wenn die datei bereits existiert, suche den entsprechenden tag und verändere den eintrag.
(3) wenn die datei bereits existiert, suche den entsprechenden tag, wenn er nicht existiert lege ihn neu an.

Punkt 2 bis 3 kriege ich einfach nicht hin.
Mir ist der letzte schritt, nach dem verändern in Methode 2, nicht klar, was ich im anschluss speichern muss, damit die daten nur verändert werden, alles existierende aber noch bestehen bleibt.
bisher konnte ich nach einigem ausprobieren, immer nur alles neu schreiben.

so wie der code ist, wirft er eine exception, wenn ich den code verändern will:
Exception in thread "main" org.jdom.IllegalAddException: The element "root" could not be added as the root of the document: The Content already has an existing parent document
wenn ich ihn komplett neu schreibe, funktioniert er wunderbar.
der fehler liegt in zeile 19 in methode 1, weil er root schreiben will.
root existiert aber bereits. was kann ich also sonst schreiben?
current aus methode 2, mein aktuelles tag, habe ich bereits versucht, da macht er einfach gar nichts.

ich hab keine ahnung mehr, nach 2 tagen seh ich den wald vor lauter bäumen nicht mehr.


Methode1 : Hier fängt alles an

```
public void loginPruefen( String auftragsNr, Flag flag ) {
        Element flags = new Element( "flags" );
        String datei = FCP_System.STAMMVERZEICHNIS + FCP_System.AUFTRAGSVERZEICHNIS + "/" + auftragsNr + "/flags.xml";
        Element root = new Element( "root" );

        SAXBuilder builder = new SAXBuilder();
        // Wenn Datei bereits vorhanden, beginne Suche.
        try {
            Document doc = builder.build( datei );
            root = doc.getRootElement();
            loginPruefenSuche( root, auftragsNr, flag );
            // ...wenn Datei noch nicht vorhanden.
        } catch( Exception ex ) {
            flags.addContent( new Element( "aid" ).addContent( auftragsNr ));
            flags.addContent( new Element( flag.getAbgeschlossen( "name" ) ).addContent( flag.getAbgeschlossen( "value" ) ));
            root.addContent( flags );
            FCP_System.ordnerAnlegen( FCP_System.STAMMVERZEICHNIS + "/auftraege/" + auftragsNr );
        }
        Document dokument = new Document( root );
        saveXML( datei, dokument );
        System.out.println("speichern");
    }
```

Methode2 : Rekursive Suche nach dem tag

```
private void loginPruefenSuche( Element current, String auftragsNr, Flag flag ) {
        String datei = FCP_System.STAMMVERZEICHNIS + FCP_System.AUFTRAGSVERZEICHNIS + "/" + auftragsNr + "/flags.xml";

        // Wenn tag gefunden...
        if ( current.getName().equals( "abgeschlossen" ) ) {
            // ...setze neuen Text.
            current.setText( flag.getAbgeschlossen( "value" ) );
        } else {
            List children = current.getChildren();
            Iterator iterator = children.iterator();
            while ( iterator.hasNext() ) {
                Element child = (Element) iterator.next();
                loginPruefenSuche( child, auftragsNr, flag );
            }
        }
    }
```

Methode3 : Speichern des XML

```
public void saveXML(String datei, Document document) {
        try {
                FileOutputStream fos = new FileOutputStream(datei, false);
                XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
                out.output(document, fos);
                fos.close();

        } catch (IOException ioe) {
                ioe.printStackTrace();
        } catch (Exception e) {
                e.printStackTrace();
        }
    }
```


----------



## Noctarius (13. Apr 2011)

Kannst das auch mit Lycia machen:

```
public class MyTransformer {

	@TagTransformer( {
		@Tag(value = "abgeschlossen")
	} )
	public Element transform(final Element current, @ContextObject final Flag flag, final DefinitionBuilder definitionBuilder) {
		Element copy = (Element) definitionBuilder.getDocument().importNode(current, false);
		copy.setText( flag.getAbgeschlossen( "value" ) );

		return copy;
	}

	public void doIt(final Flag flag) throws Exception {
		final String datei = FCP_System.STAMMVERZEICHNIS + FCP_System.AUFTRAGSVERZEICHNIS + "/" + flagHolder.auftragsNr + "/flags.xml";

		FluentBuilder<Flag> builder = FluentBuilder.prepare();
		LyciaParser<Flag> parser = builder.parser(FluentBuilder.pojoParser(this)).configure(FluentBuilder.validateSchema(false), FluentBuilder.contextObject(flag)).build();

		Document document = parser.transform(new File(datei));

		save(datei, document);
	}

	private void saveXML(final String datei, final Document document) {
	try {
		FileOutputStream fos = new FileOutputStream(datei, false);
		XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
		out.output(document, fos);
		fos.close();
 
	} catch (IOException ioe) {
		ioe.printStackTrace();
	} catch (Exception e) {
		e.printStackTrace();
	}
    }

}
```

Alternativ kannst auch direkt die DOM-API nutzen, in diesem einfachen Fall vermutlich die schnellste Version:

```
public class MyTransformer {

	public void doIt(final Flag flag) throws Exception {
		final String datei = FCP_System.STAMMVERZEICHNIS + FCP_System.AUFTRAGSVERZEICHNIS + "/" + flagHolder.auftragsNr + "/flags.xml";

		final Document document = builder.build( datei );
		final NodeList list = document.getElementsByTagName("abgeschlossen");

		for (final int i = 0; i < list.getLength(); i++) {
			final Node item = list.item(i);
			item.setText( flag.getAbgeschlossen( "value" ) );
		}

		save(datei, document);
	}

	private void saveXML(final String datei, final Document document) {
	try {
		FileOutputStream fos = new FileOutputStream(datei, false);
		XMLOutputter out = new XMLOutputter(Format.getPrettyFormat());
		out.output(document, fos);
		fos.close();
 
	} catch (IOException ioe) {
		ioe.printStackTrace();
	} catch (Exception e) {
		e.printStackTrace();
	}
    }

}
```


----------



## ForenDaddy (13. Apr 2011)

das dom-api beispiel funktioniert leider nicht.
document kann nicht mit getElementsByTagName("abgeschlossen"); verwendet werden.
das document stammt aus der dom-api, somit gibt es diese methode nicht.
die java api hat diese methode, aber dann ist das document nicht mit builder.build(datei) kompatibel.

was ein versions chaos.

*NACHTRAG:*
jetzt funktionierts. nach einer laaaaaaaaaangen mittagspause, hatte ich wieder etwas den kopf frei und da ist mir ein punkt ins auge gefallen.
in zeile 20 hatte ich root und nicht doc übergeben. daher habe ich das xml immer neu gemacht auf basis von root und nicht auf dem bereits existierenden doc.
dann noch ein paar kleine anpassungen und es funzt mit den anderen beiden methoden zusammen.
aber trotzdem echt schade, dass man die funktion getElementByID oder getElementByName nicht nutzen kann. das würde das leben gleich leichter machen.


```
public void setFlag( String auftragsNr, Flag flag ) {
        Element flags = new Element( "flags" );
        String datei = FCP_System.STAMMVERZEICHNIS + FCP_System.AUFTRAGSVERZEICHNIS + "/" + auftragsNr + "/flags.xml";
        Element root = new Element( "root" );
        Document doc = new Document( root );

        SAXBuilder builder = new SAXBuilder();
        // Wenn Datei bereits vorhanden, beginne Suche...
        try {
            doc = builder.build( datei );
            root = doc.getRootElement();
            setFlagSuche( root, auftragsNr, flag );
            // ...wenn Datei noch nicht vorhanden.
        } catch( Exception ex ) {
            flags.addContent( new Element( "aid" ).addContent( auftragsNr ));
            flags.addContent( new Element( flag.getAbgeschlossen( "name" ) ).addContent( flag.getAbgeschlossen( "value" ) ));
            root.addContent( flags );
            FCP_System.ordnerAnlegen( FCP_System.STAMMVERZEICHNIS + "/auftraege/" + auftragsNr );
        }
        saveXML( datei, doc );
    }
```


----------



## Noctarius (13. Apr 2011)

Welche DOM-API nutzt du denn? Die vom W3C kennt diese Funktion:
Document (Java Platform SE 6)


----------



## ForenDaddy (13. Apr 2011)

ich nutze jdom v1.1.1 von JDOM

wenn die das hat, hätte ich mich wohl besser für dom entschieden :shock:
egal, jetzt funzt. beim nächste mal parsen werde ich dom den vorzug geben.


----------

