Note
Sorry for the long post in advance, although I'd rather put as much information as possible, rather than fill in the blanks when necessary.
Notice that I also marked this as Delphi, and I own and still use Delphi XE. Now I use Lazarus as my main IDE, I just can not afford to buy newer versions of Delphi, and now Lazarus is becoming more stable, which makes me need to switch to Lazarus.
For this question, I turned on the zip application with the project source, although it is written in Lazarus, and this will really help with the question I have, so the comments are in the first paragraph.
Overview
In the question, I have an object that owns several classes as TLists.
I present this data in Treeview, and there is no way to know how many levels and nodes will be present in the tree, because they are dynamically created at runtime. One limitation that I set is that the top-level nodes will be fixed, that is, they cannot be deleted or renamed - this is what I will call RootGroups.
The Treeview will be populated with elements and groups, each node added to the Treeview will have its own object assigned to the data to correctly identify each element. I am going to show an example screenshot now to give a better idea before continuing:

As you can see, I have the top two most nodes, Object1Root and Object2Root. If you notice the buttons on the right, they allow you to add a group and elements to the Treeview, but they become disabled if they do not belong to that part of the Treeview. For example, you cannot add Object2Group or Object2Item to Object1Root.
Basically, everything in Treeview has its own pointer to an object. Each object I get from the base object. This base object has properties for storing the position where it is in the Treeview, for example:
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;
Then I can get other classes from the base object, for example:
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;
The main object that contains all these classes is as follows:
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;
When I save the main object in XML, I first iterate over all the TreeView and then assign node data to each object, such as Parent, Level, Index, etc. The output XML file based on the first image will look like this:

Note. Parts of SomeVal are not important, as I never worried about writing anything to objects.
Indeed, what I should do is Save to XML in the same way as Treeview shows. I'm not too familiar with XML, because I can still handle it, but I think the result should look something like this: (written in Notepad)
<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>
Then I could load the TreeView from XML. The problem is that I really know how to save XML, as I currently have, I know some kind of recursion, etc. Necessary, and it is here that I will fight and, in particular, rebuild the tree from an XML file.
application
It took me several hours to break my actual project code into an example that is easier to read and understand, it is written in Lazarus and uses the OmniXML library, I included only the original units that do not have a project file.
Download it here (password is stackoverflow): http://www34.zippyshare.com/v/16401041/file.html
Ultimately my question is:
- How to save XML in the correct hierarchical structure.
- How to load XML and rebuild Treeview as it was before saving.
Thank you very much.