Saturday, 25 April 2009

Implementación de persistencia de objetos en delphi mediante XML

Delphi no dispone de muchos sistemas para no decir ninguno que implemente la persistencia de Objetos como Java por ejemplo. Y como dice el pensamiento pragmático: no intentes diseccionar una rana, constrúyete tú una de nueva!. Pues allá vamos!.

Lo que he hecho, es crear las clases, y estas implementan unos métodos WriteToXML y ReadFromXML que guardan su contenido en un fichero XML. Por lo tanto cada instancia de clase, guarda todo su contenido en el fichero que se le pasa, y luego también puede recuperar todo su contenido a través de este.

Aquí os dejo un ejemplo bastante completo de mi última aplicación ThundaxSaveSeries, que permite guardar listas de series (Lost, Anatomia de Grey, 24h, Big bang, etc.) y queráis tener un pequeño registro donde indicar la temporada del capítulo, si lo habéis descargado, si lo habéis visto, etc. A mi me va bastante bien, ya que es mas portable que un excel.


En este ejemplo podéis ver como hago las llamadas a IXMLDocument, y accedo a sus nodos mediante IXMLNode.

unit Lib_Series;

interface

uses
Contnrs, SysUtils, XMLDoc, XMLIntf;

type
TEstado = (Vista, Descargada, Pendiente);

TCapitulo = class(TObject)
numero: integer;
Temporada: integer;
estado: TEstado;
constructor Create(temporada: integer; numero: integer; estado: TEstado);
function WriteToXML(XMLDoc: IXMLDocument; iXMLRootNode: IXMLNode; sNode: string): IXMLNode;
function ReadFromXML(XMLDoc: IXMLDocument; iXMLRootNode: IXMLNode): IXMLNode;
end;

TSerie = class(TObject)
Nombre: string;
NumCapitulos: integer;
CapituloInicial: integer;
temporada: integer;
TTemporada: TObjectList;
completa: boolean;
constructor Create(Nombre: string; Temporada: integer; NumCapitulos: integer; tieneCapituloZero: boolean);
function WriteToXML(XMLDoc: IXMLDocument; iXMLRootNode: IXMLNode; sNode: string): IXMLNode;
function ReadFromXML(XMLDoc: IXMLDocument; iXMLRootNode: IXMLNode; sNode: string): IXMLNode;
end;

TListaSeries = class(TObject)
ListaSeries: TObjectList;
constructor Create();
destructor Destroy(); override;
procedure WriteToXML(sArchivo: string);
procedure ReadFromXML(sArchivo: string);
end;

implementation

{ TListaSeries }

procedure TListaSeries.ReadFromXML(sArchivo: string);
var
Document: IXMLDocument;
iXMLRootNode, iXMLRootNode2: IXMLNode;
objSerie: TSerie;
begin
Document := TXMLDocument.Create(nil);
try
Document.LoadFromFile(sArchivo);
iXMLRootNode := Document.ChildNodes.First;
iXMLRootNode2 := iXMLRootNode.ChildNodes.first;
while iXMLRootNode2 <> nil do
begin
if iXMLRootNode2.NodeName = 'Serie' then
begin
objSerie := TSerie.CreateEmpty();
objSerie.ReadFromXML(Document, iXMLRootNode2, 'Serie');
Self.ListaSeries.Add(objSerie);
end;
iXMLRootNode2 := iXMLRootNode2.NextSibling;
end;
finally
Document := nil;
end;
end;

procedure TListaSeries.WriteToXML(sArchivo: string);
var
XMLDoc: TXMLDocument;
iNode, NodeSeccio: IXMLNode;
i: integer;
objSerie: TSerie;
begin
XMLDoc := TXMLDocument.Create(nil);
XMLDoc.Active := True;
iNode := XMLDoc.AddChild('TListaSeries');
for i := 0 to ListaSeries.count - 1 do
begin
NodeSeccio := iNode.AddChild('Serie');
objSerie := TSerie(ListaSeries[i]);
if objSerie <> nil then
objSerie.WriteToXML(XMLDoc, NodeSeccio, 'Serie');
end;
XMLDoc.SaveToFile(sArchivo);
end;

function TCapitulo.WriteToXML(XMLDoc: IXMLDocument; iXMLRootNode: IXMLNode; sNode: string): IXMLNode;
begin
iXMLRootNode.attributes['numero'] := IntToStr(Self.numero);
iXMLRootNode.attributes['Temporada'] := IntToStr(Self.Temporada);
iXMLRootNode.attributes['estado'] := TEstadoToStr(Self.estado);
end;

function TCapitulo.ReadFromXML(XMLDoc: IXMLDocument; iXMLRootNode: IXMLNode): IXMLNode;
begin
Self.numero := StrToInt(iXMLRootNode.attributes['numero']);
Self.Temporada := StrToInt(iXMLRootNode.attributes['Temporada']);
Self.estado := StrToTEstado(iXMLRootNode.attributes['estado']);
end;

function TSerie.WriteToXML(XMLDoc: IXMLDocument; iXMLRootNode: IXMLNode; sNode: string): IXMLNode;
var
iNodoObjeto: IXMLNode;
i: integer;
begin
iXMLRootNode.attributes['Nombre'] := Self.Nombre;
iXMLRootNode.attributes['NumCapitulos'] := IntToStr(Self.NumCapitulos);
iXMLRootNode.attributes['CapituloInicial'] := IntToStr(Self.CapituloInicial);
iXMLRootNode.attributes['temporada'] := IntToStr(Self.temporada);
iXMLRootNode.attributes['completa'] := BoolToStr(Self.completa);
for i := 0 to Self.TTemporada.Count - 1 do
begin
iNodoObjeto := iXMLRootNode.AddChild('Capitulos');
TCapitulo(Self.TTemporada.Items[i]).GuardarEnXML(XMLDoc, iNodoObjeto, 'Capitulos');
end;
end;

function TSerie.ReadFromXML(XMLDoc: IXMLDocument; iXMLRootNode: IXMLNode; sNode: string): IXMLNode;
var
iNodoObjeto, iNodoAtributo: IXMLNode;
objCapitulo: TCapitulo;
begin
iNodoObjeto := iXMLRootNode;
if iNodoObjeto.nodeName = sNode then
begin
Self.Nombre := iNodoObjeto.attributes['Nombre'];
Self.NumCapitulos := StrToInt(iNodoObjeto.attributes['NumCapitulos']);
Self.CapituloInicial := StrToInt(iNodoObjeto.attributes['CapituloInicial']);
Self.temporada := StrToInt(iNodoObjeto.attributes['temporada']);
Self.completa := StrToBool(iNodoObjeto.attributes['completa']);
iNodoAtributo := iNodoObjeto.ChildNodes.first;
while iNodoAtributo <> nil do
begin
objCapitulo := TCapitulo.CreateEmpty();
objCapitulo.ReadFromXMLDoc(XMLDoc, iNodoAtributo);
self.TTemporada.Add(objCapitulo);
iNodoAtributo := iNodoAtributo.nextSibling;
end;
end;
end;

end.








La persistencia de los objetos mediante su XML:


  • Enlaces de interés:

Podemos encontrar proyectos Open Source, que intentar hacer la persistencia de objetos para delphi, uno de estos es "Delphi Persistent Object" y lo podemos encontrar en SourceForge. Aquí os dejo el enlace directo:
http://sourceforge.net/projects/depo/

0 comments:

Post a Comment