ShowMessage('Die Anwendung konnte nicht ausgeführt werden. Bitte überprüfen sie ihre Angaben');
end;
end;
xml.SaveToFile(MAP_NAME);
xml.Free;
end;
DIe entstehende XMLStruktur ist zb:
Code:
<?xml version="1.0" encoding="iso-8859-1" ?>
- <Objekte>
- <GLObjekt>
- <GL_POINTS ID="1">
<NumVertices>1</NumVertices>
<Texturpfad>TexturPfad</Texturpfad>
- <Vertices>
<Vertex X="0" Y="0" Z="0" />
</Vertices>
- <Textur>
<Koordinaten X="0" Y="0" />
</Textur>
- <Color>
<RGB R="0" G="0" B="0" A="0" />
</Color>
</GL_POINTS>
</GLObjekt>
</Objekte>
In den if (FileExists(MAP_NAME) = TRUE) -Block kommt spaeter noch einiges mehr.
Das Prob nun ist das NextObject:
Delphi-Quellcode:
NextObjekt := xml.root.Items.ItemNamed['Objekte'].Items.ItemNamed['GLObjekt']
Ich brauche jetz eine Möglichkeit, in Nextobject alle in GLObjekt enthaltenen Objekte zu bekommen. In diesem Fall wäre es GL_TRIANGLES, aber es könnte auch GL_QUADS usw. sein. in NextObject muss das also gespeichert sein, damit ich per
xml.root.Items.ItemNamed['Objekte'].Items.ItemNamed['GLObjekt'].Items.ItemNamed[NextObjekt].Value
draufzugreifen kann
Okay okay vergebt mir! *hände schuetzend vor sich heb*
Okay also ich musste es etwas anders lösen.
Ich speichere die Anzahl der enthaltenen Objekte - bei der Erstellung einer neuen Datei ist das logischerweise eins.
Dann durchlaufe ich eine Forschleife bis die Objektanzahl (NumObjekte) erreicht ist. Da ich nicht auf GL_TRIANGLE zugreifen kann, weil ich ja im Voraus nicht weiß, ob es überhaupt ein TRIANGLE ist oder nicht doch ein POINTS oder ein QUADS. Also heissen meine Objekte ab jetzt 'Objekt'+i. I ist - wie ihr sicherlich intelligenter Weise schon lange erkannt habt, der Incrementor der Forschleife.
Danach wird als Propertie eben dieser Objekte der DrawMode (also POINTS, QUADS etc) gespeichert.
Speichern is ja ganz einfach dann und auslesen ist nun ja auch gelöst.
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Ich will ja nicht unken. Schon mal vorab Entschuldigung dafür, dass ich heute die Rolle des Arschloches übernehmen. Okay. Okay. Der Ein oder Andere wird sich jetzt denken. "Heute?"
Aber ohne um den heißen Brei herum zu reden. Ich finde deinen XML Aufbau merkwürdig. Dieses Listenverhalten. Also abspeichern einer Anzahl und Namensgebung mit einem Index ist äußerst untypisch für XML. Bzw hast du bei Objekt3 auch 2 Vertices angegeben aber alle heißen "Vertex". Da dürftest du dann später irgendwann Probleme bekommen.
XML lebt davon, dass die Knoten einen einheitlichen Namen haben, damit es sich ein bisschen wie eine strukturierte Textdatenbank verhält. XML Typisch wäre eigentlich etwas in der Art.
Code:
<?xml version="1.0" encoding="iso-8859-1"?>
<GLObjekte>
<Objekt Name="Blah" DrawMode="GL_POINTS">
<Textur Pfad="wall.bmp" Einstellungen="etc" />
<Vertex>
<Coord X="0" Y="0" Z="0" />
// evtl auch noch einen Datentypen anhängen damit man auch
// floats sinnvoll unterstützen kann etc. Das aber nur am Rand.
// <Coord DataType="int" X="0" Y="0" Z="0" />
<TexCoord X="0" Y="0" Z="0" />
<Normal X="0" Y="0" Z="0" />
<Color R="0" G="0" B="0" A="0" />
</Vertex>
<Vertex>
<Coord X="0" Y="0" Z="0" />
<TexCoord X="0" Y="0" Z="0" />
<Normal X="0" Y="0" Z="0" />
<Color R="0" G="0" B="0" A="0" />
</Vertex>
</Objekt>
<Objekt Name="Blub" DrawMode="GL_POINTS">
<Textur Pfad="wall.bmp" Einstellungen="etc" />
<Vertex>
<Coord X="0" Y="0" Z="0" />
<TexCoord X="0" Y="0" Z="0" />
<Normal X="0" Y="0" Z="0" />
<Color R="0" G="0" B="0" A="0" />
</Vertex>
<Vertex>
<Coord X="0" Y="0" Z="0" />
<TexCoord X="0" Y="0" Z="0" />
<Normal X="0" Y="0" Z="0" />
<Color R="0" G="0" B="0" A="0" />
</Vertex>
</Objekt>
</GLObjekte>
Ich muss allerdings gestehe, dass ich keine Ahnung habe wie so etwas dann mit diesen Komponenten einzulesen bzw wegzuschreiben wäre, da ich mich mit denen überhaupt nicht auskenne. Aber da XML eigentlich für solch eine Namensgebung konzipiert wurde kann ich mir nur schwer vorstellen, dass das nicht geht. Höchstwahrscheinlich wird es aber darauf hinauslaufen, dass du nicht mehr solche Dinge sagen kannst wie ItemNamed['Textur'], da du vorraussetzt, dass die Bezeichner eindeutig sein müssen. Was aber nicht Sinn und Zweck von XML ist.
Ich denke mal es würde dann eher so sein, dass du zu der Klasse hingehst und dann sagst gib mir mal alle Items mit dem Namen "Objekt". Und dort würdest du dann eine Liste mit 2 Elementen bekommen. Bzw in einem dieser Elemente dann auch alle elemete Namens "Vertex". So nach dem Prinzip.
PS: Ich würde beim Einlesen, dass nicht immer darauf bestehen, dass du zu jedem Punkt eine Farbe oder Normale angegeben hast.
beim direkt Zugriff auf irgendwas über Items.ItemNamed['Objekte'] gibts ne lustige AV wenn es das Item nicht gibt. Immer vorher prüfen ob Items.ItemNamed['Objekte']<>nil oder in TJvSimpleXML.Options den Flag setzen das nicht bestehende Items beim Zugriff über ItemNamed direkt erzeugt werden. Beachtet man das nicht kann es ziemlich schnell passieren das es einem gerade bei großen XML Dateien die ganze Lade/Speicher routine zerlegt weil er irgendwo mittendrin mit ner AV verreckt.
Die ItemNamed funktion ist zwar ne Prima sache, aber ständigs rum gewurschtel damit kann das ganze ziemlich langsam machen da er ja jedesmal das Item mit dem Namen suchen muß was wesentlich langsamer ist als direkt über den Index zuzugreifen. Bei großen XML Dateien wird das ein echter Zeit Faktor.
Hier sparst du dir das blöde StrToInt und kannst noch einen Default Wert angeben (die ",0)") falls es das Item nicht gibt .
[Edit 2]
Noch ein allgemeiner Hinweis zum speichern von Daten mit JvSimpleXML,
wenn du irgendwo nichts anderes machst als teile einer Klassen/Record Structur als einzelne Items ins XML zu speichern dann macht es sich einfacher das Item in das man speichern will einfach per Items.Clear komplett leer zu machen und die Daten mittels Items.Add neu rein zu schreiben.
Beispiel:
du hast eine xml Datei:
Code:
<myxmlfile>
<item>
<ID>1</ID>
<Data>something</Data>
<MoreData>something else</MoreData>
</item>
<item>
<ID>2</ID>
<Data>123</Data>
<MoreData>123456</MoreData>
</item>
</myxmlfile>
Willst du jetzt in dieser Datei das Item mit ID = 1 aktualisieren (neue Settings rein schreiben) würde ich das so machen:
Code:
for n :=to XML.Root.Items.Count-1do
with XML.Root.Items.Item[n].Itemsdo
begin
if IntValue('ID')=1then
begin
Clear;
Add('Data',...);
Add('MoreData',...);
break;
end;
end;
Ist meiner persönlichen Erfarhung nach wesentlich eleganter als da jedesmal mit Items.ItemNamed['Data'].Value := zu kommen
beim direkt Zugriff auf irgendwas über Items.ItemNamed['Objekte'] gibts ne lustige AV wenn es das Item nicht gibt. Immer vorher prüfen ob Items.ItemNamed['Objekte']<>nil oder in TJvSimpleXML.Options den Flag setzen das nicht bestehende Items beim Zugriff über ItemNamed direkt erzeugt werden. Beachtet man das nicht kann es ziemlich schnell passieren das es einem gerade bei großen XML Dateien die ganze Lade/Speicher routine zerlegt weil er irgendwo mittendrin mit ner AV verreckt.
Unmöglich. denn bei jedem Start ueberprueft er ob die Datei existiert, wenn nicht legt er sie so an, wie sie eben aussehen muss.
Hat ich mir schon ueberlegt, aber dann doch wieder verworfen. naja das ändern is ja kein Prob mehr
Billi Berserker hat geschrieben:
Die ItemNamed funktion ist zwar ne Prima sache, aber ständigs rum gewurschtel damit kann das ganze ziemlich langsam machen da er ja jedesmal das Item mit dem Namen suchen muß was wesentlich langsamer ist als direkt über den Index zuzugreifen. Bei großen XML Dateien wird das ein echter Zeit Faktor.
Wie soll ich es denn sonst machen, wenn nicht mit ItemNamed?
Hier sparst du dir das blöde StrToInt und kannst noch einen Default Wert angeben (die ",0)") falls es das Item nicht gibt .
Hat ich grade geändert
Billi Berserker hat geschrieben:
Noch ein allgemeiner Hinweis zum speichern von Daten mit JvSimpleXML, wenn du irgendwo nichts anderes machst als teile einer Klassen/Record Structur als einzelne Items ins XML zu speichern dann macht es sich einfacher das Item in das man speichern will einfach per Items.Clear komplett leer zu machen und die Daten mittels Items.Add neu rein zu schreiben. Beispiel: du hast eine xml Datei:
Code:
<myxmlfile>
<item>
<ID>1</ID>
<Data>something</Data>
<MoreData>something else</MoreData>
</item>
<item>
<ID>2</ID>
<Data>123</Data>
<MoreData>123456</MoreData>
</item>
</myxmlfile>
Willst du jetzt in dieser Datei das Item mit ID = 1 aktualisieren (neue Settings rein schreiben) würde ich das so machen:
Code:
for n :=to XML.Root.Items.Count-1do
with XML.Root.Items.Item[n].Itemsdo
begin
if IntValue('ID')=1then
begin
Clear;
Add('Data',...);
Add('MoreData',...);
break;
end;
end;
Naja ob nun so oder so, mal schaun
Habe jetz auch alles in eine Funktion ausgelagert nun funkt es wunderbar
Btw: diese geschichte mit Objekt+inttostr(i) musste ich auch bei Vertex, Koordinaten und RGB anwenden, sonst haette ich sie nicht trennen können
Unmöglich. denn bei jedem Start ueberprueft er ob die Datei existiert, wenn nicht legt er sie so an, wie sie eben aussehen muss.
Was wenn die Datei die richtig gespeichert wurde vom User/einem anderen Programm nachträglich editiert wurde und fehler rein gebaut wurden? (mag sein das es jetzt bei dir nicht passieren wird, ist aber ganz allgemein durchaus möglich) Lieber komplett komplett Idiotensicher schreiben als sich dann später damit rum ärgern
Shaddow hat geschrieben:
Wie soll ich es denn sonst machen, wenn nicht mit ItemNamed? [...] Btw: diese geschichte mit Objekt+inttostr(i) musste ich auch bei Vertex, Koordinaten und RGB anwenden, sonst haette ich sie nicht trennen können
Kommt immer ganz auf die Situation drauf an. ItemNamed[''] ist immer gut um die großen Schlüssel Items zu finden, also z.b. nen "Items" tag unter dem dann alle anderen Items als extra Elemente gespeichert sind. Dann aber besser auch den Key wenn einmal gefunden abspeichern oder mit "With ... do" arbeiten damit er nicht 100 mal das gleiche item mit ItemNamed[''] sucht.
Und ansonsten einfach alle Items von 0 bis Count -1 durchgehen und gucken wann du das passende gefunden hast und dann damit weiter arbeiten. Hier kannst du dann auch in Jedes Item nen extra ID/Name Wert haben und kannst es dir sparen die Items Objekt1,Objekt2 etc. zu nennen. Was anderes als alle Items von 0 bis Count -1 durchzugehen macht ItemNamed auch nicht.
Beispiel:
deine XML Datei sieht so aus:
Code:
<Objekt1 DrawMode="GL_POINTS">
[...]
</Objekt1>
Richtig und wesentlich besser wäre (wie Lossy bereits geschrieben hat):
Code:
<Objekt DrawMode="GL_POINTS">
<ID>1</ID>
[...]
</Objekt>
Um das Item zu finden was du suchst geht du einfach alle Items von 0 bis Count -1 durch und schaust dir für Items.Item[n] den Wert 'ID' an.
also... Items.Item[n].Items.IntValue('ID');
Was anderes macht ItemNamed[''] auch nicht, nur ist es wenn du es selbst machst
a) eleganter
b) xml konform
c) wesentlich leichter zu erweitern - z.b wenn du eh alle Items von 0 bis Count - 1 brauchst gehst du sie direkt von oben nach unten durch und machst greifst nicht über Items.ItemNamed['Object'+inttostr(n)] drauf zu.
Die Sache mit dem speichern und den Key vorher leer machen klingt etwas komisch,
ist aber meine persönliche Erfahrung das es so wesentlich besser geht.
Ansonsten müßtest du es ganz korrekt so machen:
Code:
for n :=to XML.Root.Items.Count-1do
with XML.Root.Items.Item[n].Itemsdo
begin
if IntValue('ID')=1then
begin
if ItemNamed['Data'] <> nilthen ItemNamed['Data'].Value:=...
else Add('Data',...);
if ItemNamed['MoreData'] <> nilthen ItemNamed['MoreData'].Value:=...
else Add('DataMore',...);
break;
end;
end;
da ist die sache mit dem clear wesentlich hübscher
with xml.Root.Items.ItemNamed['GLObjekte'].Items.ItemNamed['Objekt']do
begin
Properties.Add('Name', ObjektName);
Properties.Add('DrawMode', DrawModeLokal);
Properties.Add('ID','1');
Properties.Add('TexturPfad', TexturPfad);
Items.Add('Vertex');
with Items.ItemNamed['Vertex'].Itemsdo
begin
Add('Coord');
with ItemNamed['Coord'].Propertiesdo
begin
Add('X',FloatToStr(Coord[0].X));
Add('Y',FloatToStr(Coord[0].Y));
Add('Z',FloatToStr(Coord[0].Z));
end;
Add('TexCoord');
with ItemNamed['TexCoord'].Propertiesdo
begin
Add('X',FloatToStr(TexCoord[0].X));
Add('Y',FloatToStr(TexCoord[0].Y));
Add('Z',FloatToStr(TexCoord[0].Z));
end;
Add('Color');
with ItemNamed['Color'].Propertiesdo
begin
Add('R',FloatToStr(Color[0].R));
Add('G',FloatToStr(Color[0].G));
Add('B',FloatToStr(Color[0].B));
Add('A',FloatToStr(Color[0].A));
end;
end;
end;
except
ShowMessage('Die Anwendung konnte nicht ausgeführt werden. Bitte überprüfen sie ihre Angaben');
end;
end;
xml.SaveToFile(MAP_NAME);
xml.Free;
end;
Und die LoadObjects(), die allerdings keine Methode sondern nur eine Funktion ist, da sie direkt die Angaben zu ALLEN Objekten auslesen soll und nicht einzeln zu jedem einzelnen Objekt:
Code:
function LoadObjects (): TRenderObjekte;
var xml: TJvSimpleXml;
RenderObjekte: TRenderObjekte;
Name, TexturPfad:string;
DrawModeLokal: GLEnum;
Coord: TCoord;
TexCoord: TTexCoord;
Color: TFarbe;
i, j, k:Integer;
begin
try
xml := TJvSimpleXML.Create(nil);
xml.LoadFromFile(MAP_NAME);
with xml.Rootdo
begin
for i:=0to Items.Count-1do///////////////////// Durchlauf aller Objekte
begin
with Items[i]do//////////////// Instanz aller Objekte
begin
////////////////// Properties Name und DrawMode //////////////////////
Ohne jetzt XML schlecht machen zu wollen, aber wieso sich die Mühe machen und Modell-Daten in XML speichern? Zum einen kann man die nicht gerade gut komprimieren, User können sie direkt bearbeiten und die Datei wird unnötig groß. Als Quell Format ist XML legitim, aber spätestens als End Format ist Schluss. Da sollte eine binäre Form gewählt werden. Das spart Platz, lässt sich in den meisten Fällen vernünftig komprimieren und der User kann es nicht mal eben manipulieren und damit evtl. das Model zerstören. Warum also die Mühe?
Hab XML mal für Konfig Dateien probiert, bin dann aber wieder zu der klassischen INI Datei übergegangen.Ist einfach komfortabler. Außer bei GUI Elemente, da finde ich XML sehr praktisch. Warum also XML für die Modelle?
Würd mich jetzt echt mal interessieren!
Registriert: Di Mai 18, 2004 16:45 Beiträge: 2623 Wohnort: Berlin
Programmiersprache: Go, C/C++
Ich muss doch auch mal was schreiben, wäre dumm wenn ich es nicht täte.
Da ich ja mit XD_Data(im forum eher bekannt als dgl meshformat) arbeite, will ich mal meine variante posten.
Der meiste Quellcode ist zum darstellen der Daten von nöten. Exporter ist eine minimal modifikation und die Daten kann man wahlweise in xml oder bin speicher/laden. Modifizieren kann man auch aber in der Regel will man ja nur lesen.
Durch das mitliefern der Typen und header infos hat man es bequemer, so kann man überprüfen ob die file für den loader gedacht ist und neben der Code validierung, kann man dann auch die Daten eines Typ mit einem Befehl(.asType) komplett laden.
Das Beispiel ist der Anfang meines Map Formates, man hat momentan mesh,texturen und ein Entity was ein statisch konfiguriertes Partikelsystem ist(ermöglicht durch FireBlade). Momentan arbeite ich am Material System und es macht gute fortschritte.
Um das Format zu erweitern ist so gut wie kein Code von nöten. Für das erweitern um Materials braucht man 1-2zeilen im exporter,1-2 zeilen in record des typs und der code zum darstellen.
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Auch wenn die Frage nicht primär an mich gerichtet war.
Mit der Größe hast du bei XML vollkommen recht. Die ist einfach nur abartig. Aber in der heutigen Zeit denke ich mal nicht mehr so ganz entscheidend.
Die Möglichkeit es selber zu editieren bzw zu sehen was drinne steckt sieht der Ein oder Andere auch als Vorteil an. Klar. Wenn es empfindliche Daten sind und später da wirklich Endbenutzer grundlegende Sachen daran ändern können ist es nicht unbedingt die taktisch beste Wahl.
Sonst sehe ich bei XML den riesen Vorteil, dass es beliebig komplexe Strukturen aufnehmen kann. Und dann auch auf Basis eines Datensatzes. Also mehrere gleiche Strukturen können damit gespeichert werden. Und dadurch, dass es sich um Text handelt kann man es später noch weiter benutzen selbst, dann wenn die Bedeutung einzelnen Bytes auf immer und Ewig vergessen wäre.
Für ein Model weiß ich auch nicht ob ich unbedingt XML benutzen würde, da alleine ein Singlewert von 4 Bytes Binär auf 12 Bytes Text anschwillt. Und das ist alleine der Wert. Es fehlt aber noch der Bezeichner. Aber ist reine Geschmackssache. Wenn man jetzt aber so level ala Wolfenstein 3D oder so abspeichern wollte wäre das für mich zu mindest wieder legitim.
Bei dem gezeigten Level Beispiel ist es auch nachvollziehbar. Die Struktur ist logisch aufgebaut und verbrät nicht unnötigen Speicher. Deswegen auch mein Bsp. mit dem GUI. Bei Strukturen die man schnell ändern will/kann ist es durchaus legitim.
Mit der Speichergröße kann ich nur bedingt zustimmen. Da ich aus dem Java Lager komme ist es mit der Speichergröße immer sehr kritisch. Man kann bei Java nicht mal eben 200MB (ein wenig übertreib) Speicher anfordern und danach wieder freigeben. Dazu ist die VM einfach nicht in der Lage, vielleicht wird sie es eines Tages sein. Derzeit kann sie es jedenfalls nicht.
Wiederwendbare Strukturen, ok. Ist ein Argument. Was ist mit Serialisierung? Wäre definitiv eine Möglichkeit, denn auch da ändert sich in der Regel die Art und Weise der Serialisierung nicht. Und Byte Werte sind bei Java fast egal, da die ihr eigenes System verfolgt
Also, nochmal in Kurzform: Meine Meinung zum XML Einsatz, alles was sensisitv ist sollte nicht als XML gespeichert werden, dazu gehören häufig auch Konfig Dateien. Vielleicht schreibt mal jemand einen guten XML Kompressor der nicht nur nach Byte Übereinkunft sondern auch über TAG Übereinkunft komprimiert.
Bei Level und Modelldaten wo effektiv sehr viele gleiche Bezeichner vorkommen wäre das eine enorme Platzersparnis
Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.