Pascal (Lazarus/Delphi)
Pascal (Lazarus/Delphi)
XML Path Performance Optimizations
See more XML Examples
Discusses some important things to know about using Chilkat paths in the Chilkat XML API.Chilkat Pascal (Lazarus/Delphi) Downloads
program ChilkatDemo;
// Demonstrates using the Chilkat Pascal wrapper via the C bridge DLL.
// Builds as a console application under Lazarus (FPC) or Delphi.
{$IFDEF FPC}
{$MODE DELPHI}
{$ENDIF}
{$APPTYPE CONSOLE}
uses
{$IFDEF UNIX}
cthreads,
{$ENDIF}
SysUtils,
CkDllLoader,
Chilkat.Xml;
// ---------------------------------------------------------------------------
procedure RunDemo;
var
success: Boolean;
xml: TXml;
licCount: Integer;
s: string;
i: Integer;
begin
success := False;
xml := TXml.Create;
// Let's load XML containing the following:
// <?xml version="1.0" encoding="utf-8"?>
// <xyz>
// <licenses>
// <license>
// <id>1234</id>
// </license>
// <license>
// <id>1234</id>
// </license>
// ...
// My sample XML contains 64,000 "license" nodes ..
// ...
// <license>
// <id>1234</id>
// </license>
// <license>
// <id>1234</id>
// </license>
// </licenses>
// </xyz>
//
success := xml.LoadXmlFile('qa_output/large.xml');
if (success <> True) then
begin
WriteLn(xml.LastErrorText);
Exit;
end;
// Iterating over the individual "license" nodes with this code snippet is
// extremely slow:
licCount := xml.NumChildrenHavingTag('licenses|license');
WriteLn('license count = ' + licCount);
i := 0;
// If "10" is changed to licCount, then it becomes apparent that this loop gets slower with each iteration.
while i < 10 do
begin
xml.I := i;
s := xml.GetChildContent('licenses|license[i]|id');
WriteLn(i + ': ' + s);
i := i + 1;
end;
// The reason it is extremely slow is that the "license[i]" part of the path passed to GetChildContent
// says: find the i'th child of "licenses" having the tag "license". Chilkat cannot assume that all
// children of an XML node have the same tag. Therefore it's not possible to directly access the i'th child.
// Internally, Chilkat must start at the 1st child and iterate until it reaches the i'th child having the
// tag "license".
// For example, imagine if the XML was like this:
// <?xml version="1.0" encoding="utf-8"?>
// <xyz>
// <licenses>
// <license>
// <id>1234</id>
// </license>
// <somethingElse>
// <a>abc</a>
// </somethingElse>
// <license>
// <id>1234</id>
// </license>
// ...
// In the above XML, the 1st "license" is the 1st child of "licenses", but the 2nd "license"
// is the 3rd child of "licenses".
// If you already know that all children have the same tag, there is a shortcut that allows
// for direct access to that child. Just leave off the tag name, like this:
i := 0;
// If "10" is changed to licCount, then we can see the time for each loop is the same, and it's fast.
while i < 10 do
begin
xml.I := i;
s := xml.GetChildContent('licenses|[i]|id');
WriteLn(i + ': ' + s);
i := i + 1;
end;
// When we pass just the index "[i]", we're saying: Get the i'th child regardless of tag.
// This is extremely fast because internally we can just access the i'th child directly.
// Another performance improvement is to call NumChildrenAt rather than NumChildrenHavingTag.
// For example:
licCount := xml.NumChildrenAt('licenses');
WriteLn('licCount = ' + licCount);
// NumChildrenAt returns the total number of children at the tag path. If we already know
// all children will have the same tag, we can just get the count.
xml.Free;
end;
// ---------------------------------------------------------------------------
begin
try
RunDemo;
except
on E: Exception do
WriteLn('Unhandled exception: ', E.ClassName, ': ', E.Message);
end;
WriteLn;
{$IFDEF MSWINDOWS}
WriteLn('Press Enter to exit...');
ReadLn;
{$ENDIF}
end.