Sample code for 30+ languages & platforms
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

Pascal (Lazarus/Delphi)
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.