Guardando y cargando vista de árbol usando XML

Nota

Lo siento de antemano por el largo post, pensé que sería mejor poner tanta información como fuera posible en lugar de llenar los huecos cuando sea necesario.

Tenga en cuenta que aunque también he etiquetado esto como Delphi y aún soy propietario de Delphi XE, ahora uso a Lazarus como mi IDE principal, simplemente no puedo permitirme comprar las versiones más nuevas de Delphi y ahora Lazarus se está volviendo más estable. Para hacer el cambio a Lázaro.

Para esta pregunta, he incluido un archivo adjunto zip con la fuente del proyecto, aunque escrito en Lazarus realmente ayudará con la pregunta que tengo, de ahí los comentarios en el primer párrafo.

Visión general

Sobre la pregunta, tengo un objeto que posee varias clases como TLists.

Represento estos datos en una vista de árbol y no hay forma de saber cuántos niveles y nodos estarán presentes en el árbol, ya que se crean dinámicamente en tiempo de ejecución. Una limitación que he establecido es que los nodos de nivel superior serán fijos, lo que significa que no se pueden eliminar ni cambiar de nombre; esto es lo que llamaré RootGroups.

La vista en árbol se rellenará con elementos y grupos, cada nodo agregado a la vista en árbol tendrá su propio objeto asignado a los datos para identificar cada elemento correctamente. Voy a mostrar una captura de pantalla de ejemplo ahora para dar una mejor idea antes de continuar:

Como puedes ver, tengo los dos nodos más altos,Object1Root yObject2Root. Si observa los botones de la derecha, permiten agregar grupos y elementos a la vista de árbol, pero se desactivan si no pertenecen a esa parte de la vista de árbol. Por ejemplo no puedes agregarObject2Group oObject2Item debajoObject1Root.

Básicamente, todo en Treeview tiene su propio puntero a un objeto. Cada objeto que estoy derivando de un objeto base. Este objeto base tiene propiedades para almacenar la posición donde se encuentra en la vista de árbol, como esta:

type
  TBaseObject = class
  private
    FName: string;
    FGroup: string;
    FNodeLevel: Integer;
    FNodeIndex: Integer;
  public
    constructor Create(AName: string);
    destructor Destroy; override;
  published
    property Name: string read FName write FName;
    property Group: string read FGroup write FGroup;
    property NodeLevel: Integer read FNodeLevel write FNodeLevel;
    property NodeIndex: Integer read FNodeIndex write FNodeIndex;
  end;

Entonces puedo derivar mis otras clases del Objeto Base, como esto:

type
  TObject1RootGroup = class(TBaseObject)
  public
    constructor Create(AName: string);
    destructor Destroy; override;

    procedure ToSave(const XMLDoc: IXMLDocument; var Root, Node: IXMLNode);
  end;

  TObject1Group = class(TBaseObject)
  public
    constructor Create(AName: string);
    destructor Destroy; override;

    procedure ToSave(const XMLDoc: IXMLDocument; var Root, Node: IXMLNode);
  end;

  TObject1Item = class(TBaseObject)
  private
    FSomeVal1: string;
    FSomeVal2: string;
  public
    constructor Create(AName: string);
    destructor Destroy; override;

    procedure ToSave(const XMLDoc: IXMLDocument; var Root, Node: IXMLNode);
  published
    property SomeVal1: string read FSomeVal1 write FSomeVal1;
    property SomeVal2: string read FSomeVal2 write FSomeVal2;
  end; 

losObjeto principal que contiene todas estas clases se ve así:

type
  TMyObject = class(TObject)
  private
    FName: string;
    FObject1Groups: TList;
    FObject1Items: TList;
    FObject2Groups: TList;
    FObject2Items: TList;
  protected
    procedure FreeObjects;
  public
    constructor Create(AName: string);
    destructor Destroy; override;

    procedure Save(FileName: string);
    function Load(Filename: string): Boolean;
  published
    property Name: string read FName write FName;

    property Object1Groups: TList read FObject1Groups;
    property Object1Items: TList read FObject1Items;
    property Object2Groups: TList read FObject2Groups;
    property Object2Items: TList read FObject2Items;
  end;

Cuando guardo elObjeto principal Para XML, primero itero todo el TreeView y luego asigno a cada Objeto los datos del nodo, como Padre, Nivel, Índice, etc. El archivo XML de salida basado en la primera imagen se vería así:

Nota: Las partes de SomeVal no son importantes ya que nunca me molesté en escribir nada en los Objetos.

Realmente, lo que debo hacer es Guardar en el XML tal como se representa la vista de árbol. No estoy muy familiarizado con XML, ya que todavía estoy tratando de entenderlo, pero creo que la salida debería verse así: (escrito en el Bloc de notas)

<XML Name="test.xml">
  <Counts Object1Groups="3" Object1Items="5" Object2Groups="2" Object2Items="1" />

  <TObject1RootGroup Name="Object1Root" Group="" NodeLevel="0" NodeIndex="0"
     <TObject1Item Name="Item1" Group="Object1Root" NodeLevel="1" NodeIndex="0" SomeVal1="" SomeVal2="" />
     <TObject1Item Name="Item2" Group="Object1Root" NodeLevel="1" NodeIndex="1" SomeVal1="" SomeVal2="" />
     <TObject1Group Name="Group1" Group="Object1Root" NodeLevel="1" NodeIndex="2" />
     <TObject1Item Name="Item3" Group="Object1Root" NodeLevel="1" NodeIndex="3" SomeVal1="" SomeVal2="" />
     <TObject1Group Name="Group2" Group="Object1Root" NodeLevel="1" NodeIndex="4" />
        <TObject1Item Name="Item1" Group="Group2" NodeLevel="2" NodeIndex="0" SomeVal1="" SomeVal2="" />
        <TObject1Group Name="Group1" Group="Group2" NodeLevel="2" NodeIndex="1" />
           <TObject1Item Name="Item1" Group="Group1" NodeLevel="3" NodeIndex="0" SomeVal1="" SomeVal2="" />  

<TObject2RootGroup Name="Object2Root" Group="" NodeLevel="0" NodeIndex="1" 
     <TObject2Group Name="Group1" Group="Object2Root" NodeLevel="1" NodeIndex="0" />
     <TObject2Group Name="Group2" Group="Object2Root" NodeLevel="1" NodeIndex="1" />
        <TObject2Item Name="Item1" Group="Group2" NodeLevel="2" NodeIndex="0" SomeVal1="" SomeVal2="" />
</XML>

Entonces podría cargar el TreeView desde el XML. El problema es que solo sé cómo guardar el XML tal como soy actualmente, sé que se necesita algún tipo de recursión, etc., y es aquí donde me costaría mucho, y en particular reconstruir el Árbol a partir del archivo XML.

Adjunto archivo

Me ha llevado algunas horas simplificar el código de mi proyecto real en un ejemplo que es más fácil de leer y entender, está escrito en Lázaro y usa elBiblioteca omniXML, Solo he incluido las unidades fuente sin archivo de proyecto.

Descárgalo aquí (la contraseña es stackoverflow):http://www34.zippyshare.com/v/16401041/file.html

En última instancia mi pregunta es:

Cómo guardar en XML con la estructura de jerarquía correcta.Cómo cargar el XML y reconstruir el Treeview exactamente como estaba antes de guardar.

Muchas gracias.

Respuestas a la pregunta(2)

Su respuesta a la pregunta