Reading distinct values from XML using XPath

delphi, delphi-2007, delphi-2010

Solution

It seems the version of the MSXML from Delphi 2007 doesn't support XPath axis. So if you decide to use the following code, import either `Microsoft XML, v3.0` or the `Microsoft XML, v6.0` type library first and then try this:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, MSXML2_TLB;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

const
  XMLString =
    '<Accounts>' +
    '<Account Number="1" DebitAmount="1000" Amount="2827561.95"/>' +
    '<Account Number="225" DebitAmount="2000"  Amount="12312.00"/>' +
    '<Account Number="236" DebitAmount="London" Amount="457656.00"/>' +
    '<Account Number="225" DebitAmount="London" Amount="23462.40"/>' +
    '<Account Number="236" DebitAmount="Bangalore" Amount="2345345.00"/>' +
    '</Accounts>';

type
  TIntegerArray = array of Integer;

function GetAccountNumbers(const AXMLString: string): TIntegerArray;
var
  I: Integer;
  XMLDOMNodeList: IXMLDOMNodeList;
  XMLDOMDocument: IXMLDOMDocument3;
begin
  XMLDOMDocument := CoDOMDocument60.Create;
  if Assigned(XMLDOMDocument) and XMLDOMDocument.loadXML(AXMLString) then
  begin
    XMLDOMNodeList := XMLDOMDocument.selectNodes('/Accounts/Account[not(@Number=preceding-sibling::Account/@Number)]/@Number');
    SetLength(Result, XMLDOMNodeList.length);
    for I := 0 to XMLDOMNodeList.length - 1 do
      Result[I] := XMLDOMNodeList.item[I].nodeValue;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  S: string;
  I: Integer;
  IntegerArray: TIntegerArray;
begin
  S := 'Account numbers: ';
  IntegerArray := GetAccountNumbers(XMLString);
  for I := 0 to Length(IntegerArray) - 1 do
    S := S + IntToStr(IntegerArray[I]) + ', ';
  Delete(S, Length(S) - 1, 2);
  ShowMessage(S);
end;

end.

Problem

I have an XML in the following format: ``` <Accounts> <Account Number="1" DebitAmount="1000" Amount="2827561.95" /> <Account Number="225" DebitAmount="2000" Amount="12312.00" /> <Account Number="236" DebitAmount="London" Amount="457656.00" /> <Account Number="225" DebitAmount="London" Amount="23462.40" /> <Account Number="236" DebitAmount="Bangalore" Amount="2345345.00" /> </Accounts> ``` How do I retreive the unique Account Numbers using Xpath? ie, I want to get the values 1, 225 and 236. This is what I did:(I'm using Delphi 2007...) ``` Const XmlStr = ' <Accounts> <Account Number="1" DebitAmount="1000" Amount="2827561.95" /> <Account Number="225" DebitAmount="2000" Amount="12312.00" /> <Account Number="236" DebitAmount="London" Amount="457656.00" /> <Account Number="225" DebitAmount="London" Amount="23462.40" /> <Account Number="236" DebitAmount="Bangalore" Amount="2345345.00" /> </Accounts>'; function GetAccountNumbers:TList; Var XMLDOMDocument : IXMLDOMDocument; accounts : IXMLDOMNodeList; accountdetail :IXMLDOMNode; i:Integer list :TList begin Result:=TList.Create; XMLDOMDocument:=CoDOMDocument.Create; XMLDOMDocument.loadXML(XmlStr); accounts:= XMLDOMDocument.SelectNodes(''./Accounts /Account[not(@Number=preceding-sibling/ Account /@Number)]'); for i := 0 to accountdetails.length - 1 do begin accountdetail := accountdetails.item[i]; //omitting the "<>nil" checks... list.Add(accountdetail.attributes.getNamedItem('Number').Nodevalue; end; end; ``` But this returns no nodes(accountdetails.length=0). Please let me know what I am missing here. Thanks, Pradeep

Original source

Related problems