Die Anwendungs-Datenstruktur enthält oft redundante Daten, die nicht unbedingt in einer Datei gespeichert werden müssen, sondern zur Laufzeit aus den gespeicherten Daten berechnet werden können. Zudem will man vielleicht Daten verschlüsselt oder sonst wie codiert in der Datei speichern. Daher ist die zu erzeugende hierarchische Tag-Struktur nicht unbedingt eine 1:1 Abbildung der Anwendungs-Datenstruktur.
Unter OOP-Richtlinien programmiert man so, dass jedes Anwendungs-Objekt Funktionen bekommt, die sich selbst in eine Tag-Struktur umwandeln oder sich selbst aus einer Tag-Struktur aufbauen können. Mehrere so erzeugte Tag-Strukturen können dann in ein Root-Tag gehängt werden, welches ins WXML-Format serialisiert und in einer Datei gespeichert werden kann. Umgekehrt liest man eine solche Datei ein, lässt das WXML-Format parsen und baut aus den so erzeugten Tags wieder die Anwendungs-Datenstruktur auf.
Unsere Anwendung soll eine Liste von Benutzern mit Benutzername, Passwort und Benutzertyp verwalten und ein paar globale Einstellungen speichern können. Die entsprechenden Objekte der Anwendung seien folgendermassen definiert:
class CAppli public Globals ' as CGlobals public UserList ' as CUserList : end class class CGlobals public Language ' as string public LastDate ' as date : end class class CUserList public Users ' as array of CUser : end class class CUser public Name ' as string public Pwd ' as string public UType ' as string : end class
Jede Klasse erhält nun je eine Funktion SaveToXml, welche aus dem Objekt eine Tag-Struktur erzeugt, und eine Funktion LoadFromXml mit der umgekehrten Funktionalität.
Diese Funktionen sind für die Klassen CGlobals und CUser sehr einfach zu implementieren:
class CGlobals : function SaveToXml() dim tag set tag = NewXmlTag( "Globals" ) tag.AddStr "Language", Language tag.AddDate "LastDate", LastDate set SaveToXml = tag end function sub LoadFromXml( aTag ) Language = aTag.GetStrByName( "Language", "de" ) LastDate = aTag.GetDateByName( "LastDate", Now ) end sub : end class class CUser : function SaveToXml() dim tag set tag = NewXmlTag( "User" ) tag.AddStr "Name", Name tag.AddStr "Pwd", Pwd tag.AddStr "UType", UType set SaveToXml = tag end function sub LoadFromXml( aTag ) if aTag is Nothing then exit sub Name = aTag.GetStrByName( "Name", "" ) Pwd = aTag.GetStrByName( "Pwd", "" ) UType = aTag.GetStrByName( "UType", "gast" ) end sub : end class
Beachte, dass die Properties der Appli-Objekte in derselben Reihenfolge aus den Tags gelesen werden (GetXxxByName), wie die Tags erzeugt wurden (AddXxx), weil dadurch die Suche nach den Tags am schnellsten geht.
Für die User-Liste sieht SaveToXml folgendermassen aus:
class CUserList : function SaveToXml() dim tag, i set tag = NewXmlArrayTag( "UserList", UBound(UserList)+1 ) for i = 0 to UBound(UserList) set tag.TagList(i) = UserList(i).SaveToXml() next set SaveToXml = tag end function : end class
In diesem Fall wird also ein Tag-Knoten (Array-Tag) erzeugt, der alle User-Daten enthält. Die erzeugte Tag-Struktur sieht schematisch folgendermassen aus:
Tag: UserList Tag: User Tag: Name Tag: Pwd Tag: UType Tag: User Tag: Name Tag: Pwd Tag: UType :
Die zugehörige Umkehrfunktion LoadFromXml sieht wiefolgt aus:
class CUserList : sub LoadFromXml( aTag ) dim sz, user, i UserList = Array() if aTag is Nothing then exit sub sz = UBound( aTag.TagList ) if zs < 0 then exit sub redim UserList( sz ) for i = 0 to sz set user = new CUser user.LoadFromXml aTag.TagList(i) set UserList(i) = user next end sub : end class
Jetzt fehlen nur noch die Funktionen auf Appli-Ebene:
class CAppli : function SaveToXml() dim rootTag set rootTag = NewXmlTag( "Appli" ) rootTag.AddTag Globals.SaveToXml() rootTag.AddTag UserList.SaveToXml() set SaveToXml = rootTag end function sub LoadFromXml( aRootTag ) if aRootTag is Nothing then exit sub Globals.LoadFromXml aRootTag.GetTagByName( "Globals" ) UserList.LoadFromXml aRootTag.GetTagByName( "UserList" ) end sub : end class
Jetzt fehlen nur noch die Funktionen CAppli.SaveToFile und CAppli.LoadFromFile:
class CAppli : sub SaveToFile( aFilename ) dim rootTag, wxmlString set rootTag = SaveToXml() wxmlString = rootTag.Serialize() FS.WriteFile aFilename, wxmlString end sub sub LoadFromFile( aFilename ) dim wxmlString, rootTag wxmlString = FS.ReadFile( aFilename ) set rootTag = NewXmlTag( "Appli" ) rootTag.Parse wxmlString LoadFromXml rootTag end sub : end class
Damit können die Appli-Daten sehr einfach in eine Datei gespeichert und wieder geladen werden:
dim Appli set Appli = new CAppli Appli.LoadFromFile "applidata.txt" : Appli.SaveToFile "applidata.txt"
Eine solche Datei applidata.txt könnte folgendermassen aussehen:
<Globals> <Language>de</> <LastDate>31.12.2009 23:59</> </Globals> <UserList> <User> <Name>Admin</> <Pwd>****</> <UType>admin</> </User> <User> <Name>Gast</> <Pwd>****</> <UType>gast</> </User> </UserList>