# Xml dateien zusammenfügen



## Issn_Kissn (8. Sep 2012)

Hallo,

Ich stehe seit 2 Tagen vor einem Problem und ich komm einfach nicht auf die Lösung.

Ich schreibe ein Program, dass ein xml file erstellt. soweit so gut. 
Der <body> des Programes habe ich geschrieben und erstellt, dieser ändert sich immer je nach der eingelesenen Datei.

Ich habe noch einen <head> der immer gleich ist. Der <head> ist schon im xml format.
Ich habe mir gedacht ich könnte ihn einfach einlesen und vor dem <body> part einfügen.
Leider funktioniert das nicht so wie ich es mir vorstelle. 

Ich habe mir gedacht ich schreibe mehrere Klassen.
Eine erstellt mir den <body> und gibt mir hier die xml-datei zurück.
Dann nehm ich eine neue Klasse und lese erst den <head> ein, dann den <body> und füge beides in eine neue fertige xml-datei ein.

Allerdings habe ich keine Idee, wie ich ein xml-file einfach parsen kann und die gegebene Struktur kopieren und in ein neues xml einfügen kann.

Kann mir bitte jemand ein par Starttipps geben?
Danke


----------



## Nardian (8. Sep 2012)

"parsen" ist schon ein gutes stichwort.

rein fürs *lesen* von XML solltest du dir einen SAX-parser anschaun. dazu gibts in java schon fertige klassen, musst nur einen listener implementieren. Ist ne ganz feine sache (und auch noch schnell)

was ich dir aber eher empfehlen würde, da du ja nicht nur lesen sondern eigentlich *auch bearbeiten / manipulieren* willst, wäre ein DOM-parser. Damit kannst du gaaanz leicht einfach ein neues Element erstellen, und einem anderen Element mit .addChild(element) dranhängen, beliebig schachteln, und mich würds wundern wenn du damit nich auch die reihnfolge von siblings verändern könntest.

MfG

[edit]
btw - was spricht bei deiner idee eigentlich dagegen, einfach zuerst das <head> zu schreiben, und danach den <body> anzufragen?
[/edit]


----------



## Issn_Kissn (8. Sep 2012)

Danke für die schnelle Antwort.

Was meinst du mit <head> schreiben?

Ich habe:

<head>
<meta> metadata </meta>
<feature value="value"> features </feature>
<feature value="value"> features </feature>
<feature value="value"> features </feature>
<feature value="value"> features </feature>
</head>

//Body wird in einer Klasse erstellt
<body>
<satz>
<terminals> terminals </terminals>
<nonterminals> nonterminals </nonterminals> //sind noch weiter verschachtelt
</satz> //gibt mehrere Sätze
</body>

Es soll so aussehen:

<corpus>
<head>
<meta> metadata </meta>
<feature value="value"> features </feature>
<feature value="value"> features </feature>
<feature value="value"> features </feature>
<feature value="value"> features </feature>
</head>

<body>
<satz>
<terminals> terminals </terminals>
<nonterminals> nonterminals </nonterminals> //sind noch weiter verschachtelt
</satz> //gibt mehrere Sätze
</body>
</corpus>

Da ich von dem <head> eine Vorlage habe würde ich den gern einfach rein kopieren, so wie er ist, um nicht nochmal alle Befehle ausführen zu müssen um in das Document schreiben zu können.
Oder werde ich da nicht drum herrum kommen?

Ich hatte 2 Lösungsansätze, der eine war zuerst <body> zu erstellen, speichern, extra Klasse um beide zusammen zufügen und dann ein neues Document mit root erstellen.
Die andere war einfach <head> zu importieren.
Und die letzte wäre, alles abzutippen und die tags selbst zu erstellen.

Ich kenn mich leider mit DOM zu wenig aus, bzw. da ich erst seit kurzem programmieren kann, weiß ich nicht wie ich das Problem lösen könnte.

Wenn es nicht anderst geht, werd ich wohl die tags alle einzeln einfügen müssen.


----------



## Nardian (8. Sep 2012)

hmm.. auch wenns mMn von XML-sicht her nicht gerade schön ist, was spricht dagegen dass du sowas machst


```
String xml = "<corpus>\n"+
"<head>\n"+
"<meta> metadata </meta>\n"+
"<feature value="value"> features </feature>\n"+
"<feature value="value"> features </feature>\n"+
"<feature value="value"> features </feature>\n"+
"<feature value="value"> features </feature>\n"+
"</head>\n";

xml += erstelleBody();
xml += "</corpus>\n";
```

und diesen String dann einfach in eine xml-Datei speichern?


----------



## Issn_Kissn (8. Sep 2012)

Ok das hab ich jetzt nicht ganz verstanden. Muss ich das dann für jedes feature machen?

Ich habe jetzt eine helpermethode gemacht die mir ein String mit dem <head> zurück gibt. Aber leider weiß ich noch nicht wie ich das in das Document schreiben kann.

Ich hab eine methode convertToXml. In dieser lese ich eine Datei ein und mache daraus ein Document. Ich hab eine extra save methode, die mir das Document in eine xml-datei schreibt.
Aber ich weiß nicht ob mich das weiter bringt...


----------



## Nardian (8. Sep 2012)

oke - jetzt hast du mich verwirrt 

kannst du vielleicht code posten? Komme nicht ganz mit was du nun konkret verwendest (also ob du nur mit String arbeitest, oder eigene methoden hast die dir aus ner klasse XML erzeugen oder sowas)...

wie gesagt, wenn du mir code zeigen kannst, kann ich dann wohl besser verstehn wo das problem ist


----------



## Issn_Kissn (8. Sep 2012)

Ich bin selbst verwirrt weil ich nicht weiß wo ich anfangen soll...


```
public static Document convertToXml(String file) throws ParserConfigurationException, FileNotFoundException, TransformerConfigurationException, TransformerException, IOException, SAXException {

        int sentenceCount = 0;
        //creating an empty xml document
        DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
        Document doc = docBuilder.newDocument();


        //creating a xml tree
        Element root = doc.createElement(XML_CORPUS);
        root.setAttribute(XML_XMLS, "http://www.w3.org/2001/XMLSchema-instance");
        root.setAttribute(XML_XSI, "/home/marisa/Dropbox/TextTechnology/TexTechProject/TigerXML.xsd");
        root.setAttribute(XML_ID, "tubadz-rel-700-Dependenz");

//hier will ich den <head> einfügen, was so nicht funktioniert...
//create the head element
        FileReader fr = new FileReader("head.xml");
        BufferedReader br = new BufferedReader(fr);
        String lineHeader="";
        String outputHeader="";
        Element head = doc.createElement("head");
        while((lineHeader = br.readLine()) !=null){
            //bw.write(line); 
            
            System.out.println(lineHeader);
            head.setTextContent(lineHeader);
            
        }  
        root.appendChild(head);


 //create the body element
        Element body = doc.createElement("body");

//hier erstelle ich innerhalb der methode noch den <body>
//als returnvalue gebe ich ein Document zurück, dass ich in einer save methode in eine xml-datei //umschreibe.
```


----------



## Nardian (8. Sep 2012)

du verwendest doch schon DOM 

aus einem anderen beispiel hab ich das hier gefunden:


```
File fXmlFile = new File("c:\\file.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(fXmlFile);
doc.getDocumentElement().normalize();
```

damit ersparst du dir das zeilenweise einlesen. kann sein dass du damit ein komplett neues XML bekommst, mit eigenem root und so.. sollte aber kein großes problem sein, einfach nach dem head innerhalb von dem neuen xml suchen, und den eins zu eins in dein XML appenden.


Wenn ich jetz dein problem falsch verstanden habe, sorry... der code sieht an sich ganz gut aus, wenn man auch das einlesen des heads einfacher machen kann  (bzw bin mir nicht sicher ob deines funktioniert... hab sowas noch nie gemacht, könnt aber gut sein dass es doch geht - weiß es nicht)


----------



## Issn_Kissn (8. Sep 2012)

Danke ich werde das versuchen.

Ich glaub du hast mein Problem richtig verstanden.
Ich versuch mich gleich einmal daran und schau ob es was wird 

danke


----------



## Issn_Kissn (8. Sep 2012)

Hey,

also ich bin jetzt soweit, dass ich die root einfach weggelassen habe und erst mal versucht habe <body> und <head> zusammen zusetzen. Das hat super mit dem parser funktioniert und ich kann jetzt ein xml-file erstellen, dass <body> und <head> enthält.

Jetzt muss ich nur noch den root herum bauen.
Mein Problem ist, dass wenn ich das Document mit toString() umwandle und dann als setTextContent setzt, sind natürlich die Zeichen auch als String. Also < als &lt;

kann ich auch documente direkt einsetzen?


----------



## Nardian (8. Sep 2012)

hab nich getestet ob das geht, aber du könntest so etwas versuchen (erspart dir wieder das setTextContent  )


```
// das alte zeug
File fXmlFile = new File("c:\\file.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(fXmlFile);
doc.getDocumentElement().normalize();
		

// ab hier neu
NodeList nodeList = doc.getChildNodes();

Document mainDoc = dBuilder.newDocument();
Element root = mainDoc.createElement("root");

for(int i = 0; i < nodeList.getLength(); i++){
	root.appendChild(nodeList.item(i));
}
```


----------



## Issn_Kissn (9. Sep 2012)

Ich hab eine Lösung. Zwar nicht schön aber selten.

Ich habe eine saveCorpus methode in der ich via Transformer und FileWriter die Documente in ein xml-file speicher.
Hier habe ich einfach an dem outputString meine root als Strings eingetragen.

Naja so siehts zumindest so aus wie ich es haben möchte 

Danke für eure Hilfe und falls jemand doch noch eine schönere Lösung hat, bitte Bescheid geben.


----------



## Noctarius (9. Sep 2012)

Schau mal ob dir XInclude hilft


----------

