eigener XML-Editor
eigener XML-Editor
Hi Forum,
ich versuche gerade ein simplen XML-Editor zu basteln.
Dieser soll mir eine Lokale xml-Datei, die zur Steuerung einer Flash-Präsentation benutzt wird editieren.
Die xml-Datei hat einen immer wiederkehrenden Aufbau und hat eigentlich nur 3 verschiedene DOM-Elenente.
Soweit die Vorgeschichte...
Das einlesen der xml-Datei in ein QDomDocument funktioniert soweit. Das ausgeben in eine neue Datei auch.
Jetzt geht es um die Veränderung der Daten.
Ich habe gedacht, optisch wäre ein TreeWidget recht schön, das beim anklicken des jeweiligen Elementes die Eigenschaften (Knoten-Attributes) in Textfeldern anzeigt, und editieren lässt. Es soll auch möglich sein, neue Elemente einzufügen.
An die Elemente komme ich per
QDomNodeList QDomNode::childNodes () const
Leider sind die Elemente im Dom-Baum nicht eindeutig, oder hat jedes eine ID? Wie kann ich eine Löschung oder Verschiebung am besten bewerkstelligen? Ich denke beim TreeWidge könnte man den Index des angeklickten Elementes zurückgeben und ein Signal schicken, aber wie krieg ich das passende Dom-Element.
Fazit: Ich suche nach der bestmöglichen Variante die xml-Datei optisch darzustellen, und diese Darstellung direkt mit den Daten zu verknüpfen.
Vielen Dank für jede Anregung die ihr mir geben könnt!
ich versuche gerade ein simplen XML-Editor zu basteln.
Dieser soll mir eine Lokale xml-Datei, die zur Steuerung einer Flash-Präsentation benutzt wird editieren.
Die xml-Datei hat einen immer wiederkehrenden Aufbau und hat eigentlich nur 3 verschiedene DOM-Elenente.
Soweit die Vorgeschichte...
Das einlesen der xml-Datei in ein QDomDocument funktioniert soweit. Das ausgeben in eine neue Datei auch.
Jetzt geht es um die Veränderung der Daten.
Ich habe gedacht, optisch wäre ein TreeWidget recht schön, das beim anklicken des jeweiligen Elementes die Eigenschaften (Knoten-Attributes) in Textfeldern anzeigt, und editieren lässt. Es soll auch möglich sein, neue Elemente einzufügen.
An die Elemente komme ich per
QDomNodeList QDomNode::childNodes () const
Leider sind die Elemente im Dom-Baum nicht eindeutig, oder hat jedes eine ID? Wie kann ich eine Löschung oder Verschiebung am besten bewerkstelligen? Ich denke beim TreeWidge könnte man den Index des angeklickten Elementes zurückgeben und ein Signal schicken, aber wie krieg ich das passende Dom-Element.
Fazit: Ich suche nach der bestmöglichen Variante die xml-Datei optisch darzustellen, und diese Darstellung direkt mit den Daten zu verknüpfen.
Vielen Dank für jede Anregung die ihr mir geben könnt!
Elemente in XML haben von haus aus keine ID
Elemente innerhalb einer auflistung sind auch nicht indiziert ....
Das heisst, die reihenfolge der Elemente ist undefiniert. der parser koennte es so machen, aber auch so ...
DU solltest dein Programm so gestalten, das es dem programm auch egal ist.
Brauchst du bei deinen elementen eine ID, kannst/musst du das in deiner Applikation abhandeln ... also Konsistenzchecks oder so ...
zusaetzlich kannst Du in deinem xml einiges "sicherstellen" indem ne passende schema datei anlegst und gegen die validieren laesst.
Also in deinem Fall ....
wenn die reihenfolge deiner elemente keine bedeutung hat (fuer die praesentation) dann solltest denen auch keine bedeutung verpassen und die reihenfolge sollte dir auch schnuppe sein !
Ciao ...
Elemente innerhalb einer auflistung sind auch nicht indiziert ....
Das heisst, die reihenfolge der Elemente ist undefiniert. der parser koennte es so machen, aber auch so ...
DU solltest dein Programm so gestalten, das es dem programm auch egal ist.
Brauchst du bei deinen elementen eine ID, kannst/musst du das in deiner Applikation abhandeln ... also Konsistenzchecks oder so ...
zusaetzlich kannst Du in deinem xml einiges "sicherstellen" indem ne passende schema datei anlegst und gegen die validieren laesst.
Also in deinem Fall ....
wenn die reihenfolge deiner elemente keine bedeutung hat (fuer die praesentation) dann solltest denen auch keine bedeutung verpassen und die reihenfolge sollte dir auch schnuppe sein !
Ciao ...
@RHBaum
bsp.:
Dann wären z.B. eintrag oder titel Elemente.
Und wenn man mit der Funktion
QDomDocument::setContent(...)
die Datei einliest wird sehr wohl die genaue Reihenfolge der Elemente beachtet!
meinDomDocument.toString() liefert also immer das gleiche Ergebniss, und das ist sehr wichtig für meine Präsentation weil ja sonst die einzelnen Folien durcheinanadergeschmissen werden.
Was der Parser nicht macht, ist die genaue Reihenfolge der Element-Atributes zu übernehmen.
ein
<title version="1.0" aktualisiert="ja" aktiv="nein">Hallo<title>
kann also schnell mal zu einem
<title aktualisiert="ja" aktiv="nein" version="1.0">Hallo<title>
werden
scheint mir aber bisher noch keine Probleme zu machen.
Ich hatte glaub ich aber gestern noch ein Denkfehler drin. Wenn ich dynamisch+rekursiv ein treeWidget auffülle, kann ich ja in jedem Tree-Item gleich eine Referenz zu seinen zugehörigen xml-Elementknoten abspeichern.
Die frage ist nur wie???
Stellen wir uns mal vor ich habe die obige xml-Datei eingelesen. Wie kann ich jetzt auf den Knoten <stichwort>Köln</stichwort> zugreifen?
Mit referenzZuKnoten.clear(); würde der sich nämlich komfortabel löschen lassen.
Das kann doch nicht sein, das der Parser das so zufällig macht, das man auf bestimmte knoten kaum zugreifen kann und sich durch den ganzen xml-Baum hangeln muss.
Sprechen wir da von den selben Elementen?Das heisst, die reihenfolge der Elemente ist undefiniert. der parser koennte es so machen, aber auch so ...
bsp.:
Code: Alles auswählen
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<verzeichnis>
<titel>Wikipedia Städteverzeichnis</titel>
<eintrag>
<stichwort>Genf</stichwort>
<eintragstext>Genf ist der Sitz von ...</eintragstext>
</eintrag>
<eintrag>
<stichwort>Köln</stichwort>
<eintragstext>Köln ist eine Stadt, die ...</eintragstext>
</eintrag>
</verzeichnis>Dann wären z.B. eintrag oder titel Elemente.
Und wenn man mit der Funktion
QDomDocument::setContent(...)
die Datei einliest wird sehr wohl die genaue Reihenfolge der Elemente beachtet!
meinDomDocument.toString() liefert also immer das gleiche Ergebniss, und das ist sehr wichtig für meine Präsentation weil ja sonst die einzelnen Folien durcheinanadergeschmissen werden.
Was der Parser nicht macht, ist die genaue Reihenfolge der Element-Atributes zu übernehmen.
ein
<title version="1.0" aktualisiert="ja" aktiv="nein">Hallo<title>
kann also schnell mal zu einem
<title aktualisiert="ja" aktiv="nein" version="1.0">Hallo<title>
werden
scheint mir aber bisher noch keine Probleme zu machen.
Ich hatte glaub ich aber gestern noch ein Denkfehler drin. Wenn ich dynamisch+rekursiv ein treeWidget auffülle, kann ich ja in jedem Tree-Item gleich eine Referenz zu seinen zugehörigen xml-Elementknoten abspeichern.
Die frage ist nur wie???
Stellen wir uns mal vor ich habe die obige xml-Datei eingelesen. Wie kann ich jetzt auf den Knoten <stichwort>Köln</stichwort> zugreifen?
Mit referenzZuKnoten.clear(); würde der sich nämlich komfortabel löschen lassen.
Das kann doch nicht sein, das der Parser das so zufällig macht, das man auf bestimmte knoten kaum zugreifen kann und sich durch den ganzen xml-Baum hangeln muss.
<unbestaetigt>
die reihenfolge der elemente fasst der xerces, und damit der qt xml parser ned an. das heisst die dinger werden fast sicher in der richtigen reihenfolge im parser kommen.
Das ist aber kein muss. andere parser keonnten die reihenfolge aendern. und haetten damit kein falsches verhalten.
</unbestaetigt>
Ohne irgendwelche indikatoren ist bei XML die reihenfolge damit eigentlich wertungssfrei.
wenn die reihenfolge bei dir eine rolle spielt, und das tut sie ja, wuerd ich auch empfehlen ein "Position" attribut mit einzufuegen ....
Wenn du z.b. schon einen node mit ner anzahl an childs hasst, hasst du eigentlich keine chance, ein weiteres element an einer ganz bestimmten Position anzufuegen. Du kannst es nur generell anfuegen, und deine Impl entscheidet, wo sie das ding hinschreibt (meist ans ende) ....
Das kann natuerlich nur funktionieren, wenn die reihenfolge wertungsfrei ist ....
waere die Reihenfolge nicht wertungsfrei, wuerde appendchild noch nen parameter benoetigen, der bestimmt an welcher position das element dann steht .... und es wuerde sicher auch move methoden fuer elemente auf gleicher ebene geben ....
Das ist nun mal "das Wesen" von XML ....
Aber lies dazu lieber die DOM spezifikation .... QDom glaub ich, implementiert bissi mehr als DOM vorschreibt ...
ueber alle elemente iterieren, und die attribute checken ^^
der XML parser nimmt einem da nix ab.
Brauchst du so Zugriffe oefters, QMap<QString,QDomNode * > ist gar kein so ungewoehnliches Gebilde in dem zusammenhang ^^
Nen (hirarisches)Modell aus ner XML struktur zu schreiben, ist auch ne gute fingeruebung, und gar ned so schwer ^^ Aber dazu gibts auch dutzende scho fertige implementierungen, die man fuer ne eigene Loesung gut zu rate ziehen kann ....
Trotz parser muss man bei xml eben doch noch ne menge selbst machen, dafuer iss der parser und xml eben flexibel ende nie !
Ciao ....
die reihenfolge der elemente fasst der xerces, und damit der qt xml parser ned an. das heisst die dinger werden fast sicher in der richtigen reihenfolge im parser kommen.
Das ist aber kein muss. andere parser keonnten die reihenfolge aendern. und haetten damit kein falsches verhalten.
</unbestaetigt>
Ohne irgendwelche indikatoren ist bei XML die reihenfolge damit eigentlich wertungssfrei.
wenn die reihenfolge bei dir eine rolle spielt, und das tut sie ja, wuerd ich auch empfehlen ein "Position" attribut mit einzufuegen ....
Wenn du z.b. schon einen node mit ner anzahl an childs hasst, hasst du eigentlich keine chance, ein weiteres element an einer ganz bestimmten Position anzufuegen. Du kannst es nur generell anfuegen, und deine Impl entscheidet, wo sie das ding hinschreibt (meist ans ende) ....
Das kann natuerlich nur funktionieren, wenn die reihenfolge wertungsfrei ist ....
waere die Reihenfolge nicht wertungsfrei, wuerde appendchild noch nen parameter benoetigen, der bestimmt an welcher position das element dann steht .... und es wuerde sicher auch move methoden fuer elemente auf gleicher ebene geben ....
Das ist nun mal "das Wesen" von XML ....
Aber lies dazu lieber die DOM spezifikation .... QDom glaub ich, implementiert bissi mehr als DOM vorschreibt ...
Die bittere Antwort:Wie kann ich jetzt auf den Knoten <stichwort>Köln</stichwort> zugreifen?
ueber alle elemente iterieren, und die attribute checken ^^
der XML parser nimmt einem da nix ab.
Brauchst du so Zugriffe oefters, QMap<QString,QDomNode * > ist gar kein so ungewoehnliches Gebilde in dem zusammenhang ^^
Nen (hirarisches)Modell aus ner XML struktur zu schreiben, ist auch ne gute fingeruebung, und gar ned so schwer ^^ Aber dazu gibts auch dutzende scho fertige implementierungen, die man fuer ne eigene Loesung gut zu rate ziehen kann ....
Trotz parser muss man bei xml eben doch noch ne menge selbst machen, dafuer iss der parser und xml eben flexibel ende nie !
Ciao ....
xml knoten überhaupt erst mal löschen
irgendwie scheitere ich gerade noch grundlegender 
Ich habe eine XML mit QDomDocument.setContent(file) geladen.
weder
noch
löschen den Knoten. Mir kommt zwar vor das er temporär gelöscht wird,
beim Speichern ist er aber einfach wieder da.
Gespeichert hab ich mit
TextStream << QDomDocument.toString() oder aber mit QDomDocument.save(TextStream)
Komischerweise funktioniert
Da bleibt dann von der XML nur die XML-Deklaration übrig, also
<?xml version='1.0' encoding='utf-8' ?>
Ich habe eine XML mit QDomDocument.setContent(file) geladen.
weder
Code: Alles auswählen
QDomDocument.removeChild(QDomDocument.documentElement().firstChild());Code: Alles auswählen
QDomDocument.documentElement().firstChild().clear();
beim Speichern ist er aber einfach wieder da.
Gespeichert hab ich mit
TextStream << QDomDocument.toString() oder aber mit QDomDocument.save(TextStream)
Komischerweise funktioniert
Code: Alles auswählen
QDomDocument.removeChild(QDomDocument.documentElement()<?xml version='1.0' encoding='utf-8' ?>
Müsste man mehr Code zu sehen ....
Aber noch mehr grundlegende Dinge:
Das DOM Modell iss nen Moloch, was den speicherverbrauch angeht. Naja, XML blaeht die Infos ja auch gehoerig auf
Eigentlich ist die haufigste vorgehensweisse bei der arbeit mit XML:
Dom Struktur einlesen, Dom Struktur in die eigene Datenstruktur ueberfuehren (konverter) Dom struktur gleich wieder wegwerfen (deleten, speicher freigeben). Zum speichern dann aequivalent : DomStructur komplett neu aus der eigenen datenstruktur erzeugen, in den STream schreiben, DomStructur gleich wieder wegwerfen.
Hat den vorteil: Man arbeitet auf nem eigenen Datenmodell, was um laengen performanter und effizienter ist.
Das eigene Datenmodell kann viel mehr abstrahieren, also ne intuitivere Schnittstelle zu den daten bereitstellen.
Es ist viel einfacher, dann aenderungen in der XML Structur vorzunehmen, oder gar statt XML andere Formate zur serialisierung anzubieten.
Ob man es braucht, muss man selbst entscheiden ...
gewoeh dir das hin und hergerutsche mit den Strings ab ^^
Wenn deine XML Structuren mal etwas groesser werden, fliegt dir der QString mal um die ohren ... ausserdem verschwendest du viel performance ... was ned sein muss.
Arbeite mit den QDomElementen direkt ....
Sollte der bevorzugte weg sein, nen XML rauszuschreiben.
Ich nehm an, das funktioniert ned, wenn der node selber noch childs hat ...
Versuch mit QDomNode::removeChild die knoten aus der struktur auszuhaengen .... das geht IMHO aber auch nur, wenn die der knoten scho leer iss ....
Aber probier mal .... notfalls musst du halt vorher rekursiv alle unterknoten loeschen.
der removte knoten existiert zwar immer noch im dom dann ... wird aber von der struktur nimmer referenziert, iss also von ausen wie geloescht, und sollte beim serialisieren nimmer mitgeschrieben werden. Ausm Speicher wird er aber erst geworfen, nachdem das QDomDocument zerstoert hasst.
Wie gesagt, ich hab das nie gebraucht, da ich immer auf der eigenen datenstruktur arbeite und nen DOM wenn ueberhaupt, nur kurz zum serialisieren erzeuge ....
Ciao ....
Aber noch mehr grundlegende Dinge:
Das DOM Modell iss nen Moloch, was den speicherverbrauch angeht. Naja, XML blaeht die Infos ja auch gehoerig auf
Eigentlich ist die haufigste vorgehensweisse bei der arbeit mit XML:
Dom Struktur einlesen, Dom Struktur in die eigene Datenstruktur ueberfuehren (konverter) Dom struktur gleich wieder wegwerfen (deleten, speicher freigeben). Zum speichern dann aequivalent : DomStructur komplett neu aus der eigenen datenstruktur erzeugen, in den STream schreiben, DomStructur gleich wieder wegwerfen.
Hat den vorteil: Man arbeitet auf nem eigenen Datenmodell, was um laengen performanter und effizienter ist.
Das eigene Datenmodell kann viel mehr abstrahieren, also ne intuitivere Schnittstelle zu den daten bereitstellen.
Es ist viel einfacher, dann aenderungen in der XML Structur vorzunehmen, oder gar statt XML andere Formate zur serialisierung anzubieten.
Ob man es braucht, muss man selbst entscheiden ...
gewoeh dir das hin und hergerutsche mit den Strings ab ^^
Wenn deine XML Structuren mal etwas groesser werden, fliegt dir der QString mal um die ohren ... ausserdem verschwendest du viel performance ... was ned sein muss.
Arbeite mit den QDomElementen direkt ....
Code: Alles auswählen
QDomDocument doc;
QTextStream out;
///
doc.save(out); mit clear wandelst du einen typisierten Node in einen untypisiertem, also einen NULL node um ....QDomDocument.documentElement().firstChild().clear();
Ich nehm an, das funktioniert ned, wenn der node selber noch childs hat ...
Versuch mit QDomNode::removeChild die knoten aus der struktur auszuhaengen .... das geht IMHO aber auch nur, wenn die der knoten scho leer iss ....
Aber probier mal .... notfalls musst du halt vorher rekursiv alle unterknoten loeschen.
der removte knoten existiert zwar immer noch im dom dann ... wird aber von der struktur nimmer referenziert, iss also von ausen wie geloescht, und sollte beim serialisieren nimmer mitgeschrieben werden. Ausm Speicher wird er aber erst geworfen, nachdem das QDomDocument zerstoert hasst.
Wie gesagt, ich hab das nie gebraucht, da ich immer auf der eigenen datenstruktur arbeite und nen DOM wenn ueberhaupt, nur kurz zum serialisieren erzeuge ....
Ciao ....
Hast wohl recht mit der eigenen Dateistruktur - Der Aufwand ist es aber nicht Wert. Im Prinzip geht es bei mir um eine XML-Datei die für eine Präsentation herhalten muss. Sie hat jedes Jahr ca um die 50 Knoten(mit wenigen Unterknoten), und wird von zig Mitarbeitern bearbeitet. Weil die keine Ahnung vom xml-Standart haben, kommt es hin und wieder vor dass die Datei "verpfuscht wird" und man dann immer suchen muss wo ein "/>" fehlt oder Anführungszeichen vergessen worden ist.
Deswegen wollte ich einen kleinen Editor basteln, damit sichergestellt wird das die XML zur steuerung der Flash-Datei immer valide ist.
http://lists.trolltech.com/qt-interest/ ... 393-0.html
Meine xml ist so ca 30 KB.
---
Zurück zu meinem Problem:
"Wer lesen kann ist klar im vorteil" - Dieses Sprichwort hat bei mir wieder vollkommen zugeschlagen. In der Doku bin ich heute nochmal drübergestolpert:
domDocument.removeChild("unterelementvomunterelement") es nicht geht, weil das vom Papa aus gelöscht werden muss
.
Find ich ja auch irgendwie ganz niedlich das nur Papa das darf, macht die Sache aber wieder um einiges komplexer. Rekursion ist wohl unumgänglich, wobei ich doch eher der Iterationsfreund bin...
P.S.:
hatte ja oben schon die QDomDocumnet.save(Textstream) Methode verwendet. Hab auch festgestellt das die wesentlich besser ist, weil da mein Input wenigstens einigermaßen formatiert wieder rauskommt.
Deswegen wollte ich einen kleinen Editor basteln, damit sichergestellt wird das die XML zur steuerung der Flash-Datei immer valide ist.
... xml ist ja eigentlich genau dafür gemacht, einfach und direkt Änderungen durchzuführen, deswegen will ich auch direkt auf dem DOM arbeiten. In nem englischen Forum hab ich das mit dem Speicherproblem auch schon gelesen. Da bläht ne 50MB xml-Datei sich im RAM auf 2GB(!!!) auf. Die dortige Löung war die Implementation von einem OpenSource XML Editor für Linux herzunehmen/umzuschreiben.DOM requires more memory. The entire document is to be kept in memory. This gives in return the ability to modify and work with the document freely in memory and then put it back to the disk. This is very handy in many situations.
http://lists.trolltech.com/qt-interest/ ... 393-0.html
Meine xml ist so ca 30 KB.
---
Zurück zu meinem Problem:
"Wer lesen kann ist klar im vorteil" - Dieses Sprichwort hat bei mir wieder vollkommen zugeschlagen. In der Doku bin ich heute nochmal drübergestolpert:
Ist klar wenn man irgendwie versucht Childelemente zu löschen mit z.B.QDomNode QDomNode::removeChild ( const QDomNode & oldChild )
Removes oldChild from the list of children. oldChild must be a direct child of this node.
Returns a new reference to oldChild on success or a null node on failure.
domDocument.removeChild("unterelementvomunterelement") es nicht geht, weil das vom Papa aus gelöscht werden muss
Find ich ja auch irgendwie ganz niedlich das nur Papa das darf, macht die Sache aber wieder um einiges komplexer. Rekursion ist wohl unumgänglich, wobei ich doch eher der Iterationsfreund bin...
P.S.:
hatte ja oben schon die QDomDocumnet.save(Textstream) Methode verwendet. Hab auch festgestellt das die wesentlich besser ist, weil da mein Input wenigstens einigermaßen formatiert wieder rauskommt.
Nein ! ^^ XML ist nur das Protokoll. DOM ist dafuer gemacht !... xml ist ja eigentlich genau dafür gemacht, einfach und direkt Änderungen durchzuführen, deswegen will ich auch direkt auf dem DOM arbeiten.
DOM eignet sich super, wenn man die daten aus dem XML immer vorhalten woll und mit den korrespondierenden Objecten gleich synchronisieren lassen will. Dann hat man nen Datenbank aehnliches Prinzip. Das faellt einem oft leichter.
Aber in der Praxis funktioniert das eben nur eingeschraenkt. die xml dateien duerfen ned wirklich gross sein, und vieles veraendern blaeht den internen cache der dom implementation meist unendlich auf und fuehrt zu Performanceproblemen.
Wobei ich denke das du an die grenzen ned kommen wirst .
Noe, wieso ???Find ich ja auch irgendwie ganz niedlich das nur Papa das darf, macht die Sache aber wieder um einiges komplexer.
Das element das loeschen willst brauchst soweiso ....
und den papa bekommst doch ganz einfach mit parentNode() !
Versuch erst mal ohne die childs zu loeschen ... vielleicht haengt er einfach den ganzen baum dann aus .... Das wuerde dir die rekursion sparen.Rekursion ist wohl unumgänglich, wobei ich doch eher der Iterationsfreund bin...
DOM Typisches Problem ist halt, das die ganzen geloeschten knoten als leichen in deiner Dom struktur Umheroxidieren.
Wenn das parsen ned allzulange dauert, kann man ja nen reloadbutton oder so einbauen, wo er das zeugs fix in ne temp datei streamt, du dein urspruengliches dom document zerstoerst und wieder erzeugst .... und vom temp aus parst.
Alternativ kannst auch die daten von dem alten DOMDoc in ein neues kopieren, die leichen sollten dann ned beruecksichtigt werden. deiner verarbeitung musst dann halt das neue doc unterschieben und alles neu synchroniseren / aufbauen ....
Ansonsten, bekommst halt ne App im guten alten Winword style ^^ alle 2h speichern, sonst fliegt einem eh alles um die ohren ^^
Ciao ...