Irrlicht - from Noob to Pro: XML in Irrlicht


Allgemeines

Bearbeiten

XML (Extensible Markup Language) ist eine Auszeichnungssprache um Daten plattform- und vor allem implemetationsunabhängig abzulegen. So kann es auf jedem Betriebssystem gespeichert werden und in jeder Sprache ein Programm geschrieben werden, welches XML lesen und schreiben kann. Ein XML-Dokument wird in normalem Text verfasst und muss gewisse Kriterien erfüllen um gültig bzw. wohlgeformt zu sein:

  • Das Dokument darf genau nur einen Wurzelknoten (Wurzelknoten = äußerster Knoten) haben
  • Alle Elemente müssen einen Anfangs- und Endauszeichner haben
  • Alle Auszeichner müssen auf ihrer jeweiligen Ebene abgeschlossen werden
  • Attribute von Elementen müssen eindeutig sein

Beispiel

Bearbeiten

Eine Datei, die mittels Irrlicht 1.7.2 erstellt wurde:

<?xml version="1.0"?>
<config> 
       <sprite>
	      <image value="image.png" />
	      <avatar value="avatar.png" />
	      <dimension x="8" y="4" />
	      <srcdimension x="32" y="48" />

	      <animation name="down" looped="1">
	            <sequence x="1" y="0" time="250" />
	            <sequence x="2" y="0" time="250" />
	            <sequence x="3" y="0" time="250" />
	            <sequence x="0" y="0" time="250" />
	      </animation>
       </sprite>
</config>

XML-Datein in Irrlicht

Bearbeiten

XML kann in Irrlicht dazu genutzt werden wichtige Informationen zu speichern und somit die Datenschicht von der Implementation zu trennen. So könnten beispielsweise die Anwendungseinstellungen (Auflösung, Farbtiefe, Renderer, Vollbildmodus) gespeichert werden, um sie beim nächsten Programmstart auszuführen. Im obigen Beispiel wurde ein Spriteformat gespeichert um 2D-Animationen zu ermöglichen. Denkbar wären auch Informationen über Karten, Level, Gegenstände und vieles mehr.

XML Schreiben

Bearbeiten

Irrlicht beitet eine Klasse IXMLWriter, mit der es möglich ist XML in eine Datei zu speichern. Dazu wird ein Zeiger vom Typ IXMLWriter erzeugt und mit Hilfe der write-Methoden die entsprechende Information erzeugt. Nachfolgender Code, soll dies Illustrieren:

//...
using namespace io; //namespace von "IXMLWriter

//...
IrrlichtDevice* device = createDevice(EDT_NULL);

//...

//Die Datei, in die geschrieben wird
IWriteFile* file = device->getFileSystem()->createAndWriteFile(filename);

//Objekt, welches XML in eine Datei schreibt
IXMLWriter* writer = device->getFileSystem()->createXMLWriter(file);

if(writer)
{
	writer->writeXMLHeader();
	writer->writeLineBreak();
	//Wurzelknoten, muss geschlossen werden!
	writer->writeElement(L"config");
	writer->writeLineBreak();

	writer->writeElement(L"knoten", true, L"name", L"ein Knoten mit 1 Attribut");
	writer->writeLineBreak();
	writer->writeElement(L"leerer Knoten", false);
	writer->writeLineBreak();
	
	//Wurzelknoten wird geschlossen
	writer->writeClosingTag(L"config");

	file->drop();
	writer->drop();
}

Mittels file->drop() und writer->drop() erzwingen wir das sofortige Speichern, da sonst erst die Datei erzeugt und gespeichert wird, wenn das Programm geschlossen wird und alle Daten aus dem Hauptspeicher auf die Festplatte geschrieben werden.

XML lesen

Bearbeiten

Um in Irrlicht XML zu lesen gibt es zwei Möglichkeiten. In Irrlicht selbst integriert gibt es die Klasse IXMLReader mit der es grundsätzlich möglich ist XML-Datein korrekt zu lesen. Ambiera hat einen eigenen XML-Reader geschrieben, der die gleiche Funktionalität liefert zudem aber auch die gängisten Text-Kodierungen unterstützt. Hier wird nur auf die irrlichteigene Klasse eingegangen.

Um XML zu lesen wird ein Zeiger auf IXMLReader erstellt und mittels einer Schleife der komplette Inhalt der Datei gelesen und ausgewertet.

<?xml version="1.0"?>
<config> 
       <message text="Hello World" times="4">
</config>
IrrlichtDevice* device = createDevice(EDT_NULL);

//...

IXMLReader* reader = device->getFileSystem()->createXMLReader(filename);

if(reader)
{
	//lies so lange, bis reader()->read() == false, gdw eof erreicht wurde	
	while(reader->read())
	{
		//Mit as für einem Element haben wir es zu tun?
		switch(reader->getNodeType())
		{
			case EXN_ELEMENT:
				if(reader->getNodeName() == stringw(L"message"))
				{
					for(unsigned int i = 0; i < reader->getAttributeValueAsInt(L"times"); i ++)
						wcout << reader->getAttributeValue(L"text") << endl;
				}
				break;

			case EXN_COMMENT:
				//Ein Kommentar
				break;

			case EXN_ELEMENT_END:
				//Ein Closing-Tag wurde gefunden
				break;
		}
	}
}