?
Solved

XMLDocument1 - Save & Load From ListView Function Needs Improving.

Posted on 2010-01-11
10
Medium Priority
?
2,918 Views
Last Modified: 2012-08-13
Hi, Today I've been playing with XMLDocument1, I've made these functions for Saving and Loading XML Files into ListView using XMLDocument1.

is there anyway to neaten the code, improve the code etc.?


Guide for the code in the code box below.
################################
//This is for the root in the <save
XMLDocument1.ChildNodes[0];

//This is for Selecting <data id="1"... Row.
XMLDocument1.ChildNodes[0].ChildNodes[1];

//This is for Extracting{Hi this is the app 2}
XMLDocument1.ChildNodes[0].ChildNodes[1].AttributeNodes.Nodes[1];

//This is the count of nodes and will bring back 4 if there are 4 data nodes.
Form1.XMLDocument1.DocumentElement.ChildNodes.Count;

//This is to Get the Values from the root which is the save node.
Form1.XMLDocument1.DocumentElement.Attributes['version'];

Guide of XML Layout
################################
<save version="now" file="downloading">
  <data id="0" note="Hi this is the app 1" url="http://1.com/" size="23453566"/>
  <data id="1" note="Hi this is the app 2" url="http://2.com/" size="2355566"/>
  <data id="2" note="Hi this is the app 3" url="http://3.com/" size="2333336"/>
  <data id="3" note="Hi this is the app 4" url="http://4.com/" size="2345556"/>
</save>

Unit: 1 of 3
###############################################################################
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, xmldom, XMLIntf, msxmldom, XMLDoc, StdCtrls, ComCtrls, ExtCtrls,
  Buttons;

type
  TForm1 = class(TForm)
    ListView1: TListView;
    XMLDocument1: TXMLDocument;
    Panel1: TPanel;
    Label1: TLabel;
    Label2: TLabel;
    Panel2: TPanel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    SpeedButton1: TSpeedButton;
    Label7: TLabel;
    SpeedButton2: TSpeedButton;
    Edit1: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure ListView1Click(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure SpeedButton1Click(Sender: TObject);
    procedure ListView1ColumnClick(Sender: TObject; Column: TListColumn);
    procedure SpeedButton2Click(Sender: TObject);
    procedure Edit1KeyPress(Sender: TObject; var Key: Char);
  private
    { Private declarations }
    LastSortedColumn: Integer;//Sorting Columns
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  Ascending: Boolean;//Sorting Columns
implementation

{$R *.dfm}
//===================Sort Column===================
function SortByColumn(Item1, Item2: TListItem; Data: integer):integer; stdcall;
begin
  if Data = 0 then
    Result := AnsiCompareText(Item1.Caption, Item2.Caption)
  else
    Result := AnsiCompareText(Item1.SubItems[Data - 1], Item2.SubItems[Data - 1]);
  if not Ascending then
    Result := -Result;
end;

procedure TForm1.ListView1ColumnClick(Sender: TObject; Column: TListColumn);
begin
  Ascending := not Ascending;
  LastSortedColumn := Column.Index;
    TListView(Sender).CustomSort(@SortByColumn, Column.Index);
end;

//===================Edit1 for Numbers Only===================
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
begin
  if not (Key in [#8, '0'..'9', DecimalSeparator]) then begin
    Key := #0;
  end
  else if (Key = DecimalSeparator) and
          (Pos(Key, Edit1.Text) > 0) then begin
    Key := #0;
  end;
end;

//===================XML===================
function Load(s:integer;n,v:string):string;
var
  a, b: IXMLNode;
  i:integer;
begin
  case s of
    0:begin
      i := 0;
      a := Form1.XMLDocument1.DocumentElement.ChildNodes.First;
      b:=Form1.XMLDocument1.DocumentElement.ChildNodes.First.ChildNodes.FindNode('save');
    try
      Repeat
        b:=Form1.XMLDocument1.ChildNodes[0].ChildNodes[i].AttributeNodes.Nodes[strtoint(v)];
        with Form1.ListView1.Items.Add do begin
          Caption := Form1.XMLDocument1.ChildNodes[0].ChildNodes[i].AttributeNodes.Nodes[0].Text;
          SubItems.Add(Form1.XMLDocument1.ChildNodes[0].ChildNodes[i].AttributeNodes.Nodes[1].Text);
          SubItems.Add(Form1.XMLDocument1.ChildNodes[0].ChildNodes[i].AttributeNodes.Nodes[2].Text);
          SubItems.Add(Form1.XMLDocument1.ChildNodes[0].ChildNodes[i].AttributeNodes.Nodes[3].Text);
        end;
        a := a.NextSibling;
        Inc(i);
      Until a = nil;
    finally

    end;
      Form1.Label7.Caption:=IntToStr(Form1.XMLDocument1.DocumentElement.ChildNodes.Count);
    end;
    1:begin
        b:=Form1.XMLDocument1.DocumentElement.ChildNodes.First.ChildNodes.FindNode('save');
        b:=Form1.XMLDocument1.ChildNodes[0].ChildNodes[strtoint(n)].AttributeNodes.Nodes[strtoint(v)];
        result:=b.Text;
    end;
  end;
end;

function Save:string;
var
  XMLDoc : TXMLDocument;
  a,b:IXMLNode;
  i: Integer;
begin
  XMLDoc := TXMLDocument.Create(nil);
  XMLDoc.Active := True;
  XMLDoc.Options:=[doNodeAutoCreate,doNodeAutoIndent,doAttrNull,doAutoPrefix,doNamespaceDecl];

  a := XMLDoc.AddChild('save');
  a.Attributes['version']:='0.05';
  a.Attributes['file']:='downloading';

  for I := 0 to Form1.ListView1.Items.Count - 1 do begin
    b := a.AddChild('data');
    b.Attributes['id']:=Form1.ListView1.Items[i].Caption;
    b.Attributes['note']:=Form1.ListView1.Items[i].SubItems[0];
    b.Attributes['url']:=Form1.ListView1.Items[i].SubItems[1];
    b.Attributes['size']:=Form1.ListView1.Items[i].SubItems[2];
  end;
  XMLDoc.SaveToFile(ChangeFileExt(ParamStr(0),'.xml'));
end;

function Populate:string;
var
  i:integer;
begin
  Form1.ListView1.Clear;
  for i := 0 to StrToInt(Form1.Edit1.Text) do
    with  Form1.ListView1.Items.Add do begin
      Caption := 'ID'+IntToStr(i);
      SubItems.Add('Note'+IntToStr(i));
      SubItems.Add('URL'+IntToStr(i));
      SubItems.Add('Size'+IntToStr(i));
    end;
  Form1.Label7.Caption:=IntToStr(Form1.ListView1.Items.Count);
  Form1.Caption:='XML - Populated into ListView1';
end;

function Display:string;
begin
  Form1.Label3.Caption:='ID: '+Load(1,inttostr(Form1.ListView1.Selected.Index),'0');
  Form1.Label4.Caption:='Note: '+Load(1,inttostr(Form1.ListView1.Selected.Index),'1');
  Form1.Label5.Caption:='URL: '+Load(1,inttostr(Form1.ListView1.Selected.Index),'2');
  Form1.Label6.Caption:='Size: '+Load(1,inttostr(Form1.ListView1.Selected.Index),'3');
end;

function Check:string;
begin
  if FileExists(ChangeFileExt(ParamStr(0),'.XML')) then begin
    Form1.XMLDocument1.LoadFromFile(ChangeFileExt(ParamStr(0),'.xml'));
    Form1.XMLDocument1.Active:=True;
    Form1.Label1.Caption:='Version: '+Form1.XMLDocument1.DocumentElement.Attributes['version'];
    Form1.Label2.Caption:='File: '+Form1.XMLDocument1.DocumentElement.Attributes['file'];
    Load(0,'','0');
    Form1.Caption:='XML - Loaded from XML File';
  end else begin
    Populate;
  end;
end;

procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
  Populate;
end;

procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
  ListView1.Clear;
  Label7.Caption:='0';
end;

procedure TForm1.ListView1Click(Sender: TObject);
begin
  Display;
end;



procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  Save;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Check;
end;

end.
###############################################################################

Source View: 2 of 3
###############################################################################
object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'XML'
  ClientHeight = 288
  ClientWidth = 466
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  Position = poDesktopCenter
  OnCloseQuery = FormCloseQuery
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object ListView1: TListView
    Left = 0
    Top = 41
    Width = 466
    Height = 166
    Align = alClient
    Columns = <
      item
        Caption = 'ID'
        Width = 111
      end
      item
        Caption = 'Note'
        Width = 111
      end
      item
        Caption = 'URL'
        Width = 111
      end
      item
        Caption = 'Size'
        Width = 111
      end>
    ReadOnly = True
    RowSelect = True
    TabOrder = 0
    ViewStyle = vsReport
    OnClick = ListView1Click
    OnColumnClick = ListView1ColumnClick
  end
  object Panel1: TPanel
    Left = 0
    Top = 0
    Width = 466
    Height = 41
    Align = alTop
    TabOrder = 1
    DesignSize = (
      466
      41)
    object Label1: TLabel
      Left = 8
      Top = 5
      Width = 64
      Height = 13
      Caption = 'Version: 0.05'
    end
    object Label2: TLabel
      Left = 8
      Top = 22
      Width = 83
      Height = 13
      Caption = 'File: downloading'
    end
    object SpeedButton1: TSpeedButton
      Left = 441
      Top = 1
      Width = 23
      Height = 22
      Caption = 'P'
      OnClick = SpeedButton1Click
    end
    object Label7: TLabel
      Left = 453
      Top = 24
      Width = 6
      Height = 13
      Alignment = taRightJustify
      Anchors = [akTop, akRight]
      Caption = '0'
    end
    object SpeedButton2: TSpeedButton
      Left = 418
      Top = 1
      Width = 23
      Height = 22
      Caption = 'C'
      OnClick = SpeedButton2Click
    end
    object Edit1: TEdit
      Left = 381
      Top = 2
      Width = 36
      Height = 20
      Alignment = taRightJustify
      TabOrder = 0
      Text = '30'
      OnKeyPress = Edit1KeyPress
    end
  end
  object Panel2: TPanel
    Left = 0
    Top = 207
    Width = 466
    Height = 81
    Align = alBottom
    TabOrder = 2
    object Label3: TLabel
      Left = 8
      Top = 6
      Width = 15
      Height = 13
      Caption = 'ID:'
    end
    object Label4: TLabel
      Left = 8
      Top = 25
      Width = 27
      Height = 13
      Caption = 'Note:'
    end
    object Label5: TLabel
      Left = 8
      Top = 44
      Width = 23
      Height = 13
      Caption = 'URL:'
    end
    object Label6: TLabel
      Left = 8
      Top = 63
      Width = 23
      Height = 13
      Caption = 'Size:'
    end
  end
  object XMLDocument1: TXMLDocument
    Options = [doNodeAutoCreate, doNodeAutoIndent, doAttrNull, doAutoPrefix, doNamespaceDecl]
    Left = 208
    Top = 112
    DOMVendorDesc = 'MSXML'
  end
end
###############################################################################

XML Content: 3 of 3
###############################################################################
<save version="0.05" file="downloading">
  <data id="ID0" note="Note0" url="URL0" size="Size0"/>
  <data id="ID1" note="Note1" url="URL1" size="Size1"/>
  <data id="ID2" note="Note2" url="URL2" size="Size2"/>
  <data id="ID3" note="Note3" url="URL3" size="Size3"/>
  <data id="ID4" note="Note4" url="URL4" size="Size4"/>
  <data id="ID5" note="Note5" url="URL5" size="Size5"/>
  <data id="ID6" note="Note6" url="URL6" size="Size6"/>
  <data id="ID7" note="Note7" url="URL7" size="Size7"/>
  <data id="ID8" note="Note8" url="URL8" size="Size8"/>
  <data id="ID9" note="Note9" url="URL9" size="Size9"/>
  <data id="ID10" note="Note10" url="URL10" size="Size10"/>
  <data id="ID11" note="Note11" url="URL11" size="Size11"/>
  <data id="ID12" note="Note12" url="URL12" size="Size12"/>
  <data id="ID13" note="Note13" url="URL13" size="Size13"/>
  <data id="ID14" note="Note14" url="URL14" size="Size14"/>
  <data id="ID15" note="Note15" url="URL15" size="Size15"/>
  <data id="ID16" note="Note16" url="URL16" size="Size16"/>
  <data id="ID17" note="Note17" url="URL17" size="Size17"/>
  <data id="ID18" note="Note18" url="URL18" size="Size18"/>
  <data id="ID19" note="Note19" url="URL19" size="Size19"/>
  <data id="ID20" note="Note20" url="URL20" size="Size20"/>
  <data id="ID21" note="Note21" url="URL21" size="Size21"/>
  <data id="ID22" note="Note22" url="URL22" size="Size22"/>
  <data id="ID23" note="Note23" url="URL23" size="Size23"/>
  <data id="ID24" note="Note24" url="URL24" size="Size24"/>
  <data id="ID25" note="Note25" url="URL25" size="Size25"/>
  <data id="ID26" note="Note26" url="URL26" size="Size26"/>
  <data id="ID27" note="Note27" url="URL27" size="Size27"/>
  <data id="ID28" note="Note28" url="URL28" size="Size28"/>
  <data id="ID29" note="Note29" url="URL29" size="Size29"/>
  <data id="ID30" note="Note30" url="URL30" size="Size30"/>
</save>

Open in new window

0
Comment
Question by:eNarc
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 5
10 Comments
 
LVL 26

Accepted Solution

by:
EddieShipman earned 2000 total points
ID: 26289927
Try the XML to Treeview code here:
http://delphi.about.com/library/weekly/aa101904a.htm

I'd use the same technique to load a TListview.
0
 
LVL 5

Author Comment

by:eNarc
ID: 26290696
Hi ES, I've been to that website, and that code on the website and many others that studied the XMLDocument and I've then complied a some functions to be able to use XMLDocument1 better, that I haven't seen on websites, and people don't even know, they'd rather use parsing functions or xml components.

I like XMLDocument1 it's perfect! cos I've now made some awesome functions with it.

for example of I wanted to load a selected entry field then I'd use this.

Load(1,inttostr(Form1.ListView1.Selected.Index),'0')

1:= the case.

inttostr(Form1.ListView1.Selected.Index):= the id of the data like which row do I want so if I wanted listview row or xml data node 3 then that would lock in on that.

'0':= is the fields within the data node.

so if I wanted URL from data 3 then I'd use

Load(1,2,'2')


I could even get with of the '2' string and just put a 2 cos when I was making it I used a edit box to switch and view selected data from the row and value.

its much better than the one on about.com, just because I've made it lol and because it targets entrys on how I want it to.

if I wanted to load all the xml data rows into the list view

Load(0,'','0');


and to be honest I could make Load(0,ListView2,'','0'); so I can then select which Listview I want to populate.

so it works really effectively, and just wanted to know how I could clean the functions up.


0
 
LVL 5

Author Comment

by:eNarc
ID: 26290720
oh just noticed that in Load function b nodes are not being used so I have taken that node out.


      a := Form1.XMLDocument1.DocumentElement.ChildNodes.First;
--->// b:=Form1.XMLDocument1.DocumentElement.ChildNodes.First.ChildNodes.FindNode('save');
    try
      Repeat
----->//b:=Form1.XMLDocument1.ChildNodes[0].ChildNodes[i].AttributeNodes.Nodes[strtoint(v)];
        with Form1.ListView1.Items.Add do begin


I've also made

function Load(s:integer;n,v:string):string;

into....

function Load(s,n,v:integer):string;

so to call it just use and display that entry into a label.

Label3.Caption:='ID: '+Load(1,Form1.ListView1.Selected.Index,0);

so this is what I'm taking about, just a clean up.

there is source and form and xml within the code.
function Load(s,n,v:integer):string;
var
  a, b: IXMLNode;
  i:integer;
begin
  case s of
    0:begin
      i := 0;
      a := Form1.XMLDocument1.DocumentElement.ChildNodes.First;
    try
      Repeat
        with Form1.ListView1.Items.Add do begin
          Caption := Form1.XMLDocument1.ChildNodes[0].ChildNodes[i].AttributeNodes.Nodes[0].Text;
          SubItems.Add(Form1.XMLDocument1.ChildNodes[0].ChildNodes[i].AttributeNodes.Nodes[1].Text);
          SubItems.Add(Form1.XMLDocument1.ChildNodes[0].ChildNodes[i].AttributeNodes.Nodes[2].Text);
          SubItems.Add(Form1.XMLDocument1.ChildNodes[0].ChildNodes[i].AttributeNodes.Nodes[3].Text);
        end;
        a := a.NextSibling;
        Inc(i);
      Until a = nil;
    finally
    end;
      Form1.Label7.Caption:=IntToStr(Form1.XMLDocument1.DocumentElement.ChildNodes.Count);
    end;
    1:begin
        b:=Form1.XMLDocument1.DocumentElement.ChildNodes.First.ChildNodes.FindNode('save');
        b:=Form1.XMLDocument1.ChildNodes[0].ChildNodes[n].AttributeNodes.Nodes[v];
        result:=b.Text;
    end;
  end;
end;

Open in new window

0
Quiz: What Do These Organizations Have In Common?

Hint: Their teams ended up taking quizzes, too.

 
LVL 26

Expert Comment

by:EddieShipman
ID: 26293785
You know, there may be a faster way to do this using XSLT. Let me take a look at it.
0
 
LVL 5

Author Comment

by:eNarc
ID: 26298383
Hi ES, I've tested the Speed of the functions and they seem really fast, I used a Performance function.

Load(1,Form1.ListView1.Selected.Index,0) averaged 52 on 30 runs using this method below.

var
  i,o:integer;
begin

  o:=0;
  for I := 0 to 30 - 1 do begin
    Performance(0);
    Load(1,Form1.ListView1.Selected.Index,0);
    Performance(1);
    o:=o+Performance(2);
  end;
  form1.edit3.Text:=inttostr(o div 30);
#######################################


the speed of 34 with 30 runs using Load(1,0,0); so the speed difference was taking out the means of accessing listview.

I'd say my function along with XMLDocument, do pretty well for speeds, Grabbing row 0 value 0 in 34 running it 30x and then averaging it to gadge a better value speed.

though I'd love to check XSLT Speeds on grabbing a selected data value, though from how I've made the function, its pretty easy to use. the component would probly be no different than XMLDocument.

This is to Load all the data from the XML File
##############################
Load(0,0,0);
see how everything is set to 0 meaning it will just load the whole xml, including the root values.
##############################

This is to load Selected Root values.
##############################
Form1.XMLDocument1.DocumentElement.Attributes['version'];
##############################

This is to load Selected data values
##############################
Load(1,Form1.ListView1.Selected.Index,1);
Load(is the switch, is the data index row, is the data node value);


its even for a function to save to a xml file
##############################
Save;

is there anything else I'm missing?
function Performance(id:int64):Int64;
//var PerformanceBegin,PerformanceEnd:Int64;//Global Vars
begin;
  result := -1;
  case id of
    0:if QueryPerformanceCounter(PerformanceBegin) then Result := PerformanceBegin;
    1:if QueryPerformanceCounter(PerformanceEnd) then Result := PerformanceEnd;
    2:Result := PerformanceEnd - PerformanceBegin;
  end;
end;

Open in new window

0
 
LVL 26

Expert Comment

by:EddieShipman
ID: 26305679
Oh, no, using XSLT to grab the node with the index you are looking for should be much faster than iterating through the nodes.
0
 
LVL 5

Author Comment

by:eNarc
ID: 26345859
Where can I download xslt component?
0
 
LVL 26

Expert Comment

by:EddieShipman
ID: 26353080
XSLT is not a component, it is using a "query language" to filter the XML.
I really meant to say XPATH, which is also a "langeauge" to filter XML.
I'm still working on it. Got a lot of irons in the fire.
0
 
LVL 5

Author Comment

by:eNarc
ID: 26353875
like parsing?
0
 
LVL 26

Expert Comment

by:EddieShipman
ID: 26354252
No, what it does is it filters out the nodes that don't meet the criteria in the path. Here's an example.
Give it a try and see if it works for you. I am doing this kind of off the top of my head so it may need to be tweaked a little bit.
Let's say you have this XML:

<?xml version="1.0" encoding="ISO-8859-1"?>
<bookstore>
  <book>
    <title lang="eng">Harry Potter</title>
    <price>29.99</price>
  </book>
  <book>
    <title lang="eng">Learning XML</title>
    <price>39.95</price>
  </book>
</bookstore>

To select all the title elements of the book 
elements of the bookstore element that have 
a price element with a value greater than 35.00, 
you would do this:

 XMLDoc.selectNodes('/bookstore/book[price>35.00]/title');

I'm working on how to iterate through the nodes using XPATH.

So iterating using XPATH on your XML something like this:

  var
    i: Integer;
    oNodelist: IXMLDOMNodeList;
    oDataNode: IXMLDOMNode;
  begin
    // This selects the downloading save node.
    oNode := selectNode('//title[@file='downloading']')
    // iterate through it's children using XPath
    for i := 0 to oXMLDoc.childNodes.length-1 do
    begin
      oNodelist := XMLDoc.selectNodes('/save/data[position()=i]');
      oDataNode := oNodeList.item[i];
      // Now you have the correct child, parse it as normal;
      if Assigned(oDataNode) then
    end;
  end;

Open in new window

0

Featured Post

New benefit for Premium Members - Upgrade now!

Ready to get started with anonymous questions today? It's easy! Learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Do you want to know how to make a graph with Microsoft Access? First, create a query with the data for the chart. Then make a blank form and add a chart control. This video also shows how to change what data is displayed on the graph as well as form…
In this video you will find out how to export Office 365 mailboxes using the built in eDiscovery tool. Bear in mind that although this method might be useful in some cases, using PST files as Office 365 backup is troublesome in a long run (more on t…
Suggested Courses
Course of the Month9 days, 9 hours left to enroll

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question