11

I am new to the delphi language, and here I have a doubt, I have a xml file called vehicle.xml.

It looks like this

<data>
<vehicle>
    <type>Car</type>
    <model>2005</model>
    <number>1568</number>
</vehicle>
<vehicle>
    <type>Car</type>
    <model>2009</model>
    <number>1598</number>
</vehicle>
</data>

My Delphi form contains three text boxes:

  • txtType
  • txtModel
  • txtnumber

While loading the page I want to display the contents of the vehicle.xml over the text box like:

  • txtType=Car
  • txtModel=2005
  • txtNumber="1568"
Mikael Eriksson
  • 136,425
  • 22
  • 210
  • 281
Banana
  • 136
  • 1
  • 1
  • 7

3 Answers3

19

Have a look at Delphi's own TXMLDocument component, for example:

uses
  ..., XMLIntf, XMLDoc;

procedure TForm1.FormCreate(Sender: TObject);
var
  Vehicle: IXMLNode;
begin
  XMLDocument1.FileName :='vehicle.xml';
  XMLDocument1.Active := True;
  try
    Vehicle := XMLDocument.DocumentElement;
    txtType.Text := Vehicle.ChildNodes['type'].Text;
    txtModel.Text := Vehicle.ChildNodes['model'].Text;
    txtnumber.Text  := Vehicle.ChildNodes['number'].Text;
  finally
    XMLDocument1.Active := False;
  end;
end;

Alternatively, use the IXMLDocument interface directly (which TXMLDocument implements):

uses
  ..., XMLIntf, XMLDoc;

procedure TForm1.FormCreate(Sender: TObject);
var
  Doc: IXMLDocument;
  Vehicle: IXMLNode;
begin
  Doc := LoadXMLDocument('vehicle.xml');
  Vehicle := Doc.DocumentElement;
  txtType.Text := Vehicle.ChildNodes['type'].Text;
  txtModel.Text := Vehicle.ChildNodes['model'].Text;
  txtnumber.Text := Vehicle.ChildNodes['number'].Text;
end;

Update: the XML in the question has been altered to now wrap the vehicle element inside of a data element, and to have multiple vehicle elements. So the code above has to be adjusted accordingly, eg:

uses
  ..., XMLIntf, XMLDoc;

procedure TForm1.FormCreate(Sender: TObject);
var
  Doc: IXMLDocument;
  Data: IXMLNode;
  Node: IXMLNode;
  I: Integer;
begin
  Doc := LoadXMLDocument('vehicle.xml');
  Data := Doc.DocumentElement;
  for I := 0 to Data.ChildNodes.Count-1 do
  begin
    Node := Data.ChildNodes[I];
    // if all of the child nodes will always be 'vehicle' only
    // then this check can be removed...
    if Node.LocalName = 'vehicle' then
    begin
      // use Node.ChildNodes['type'], Node.ChildNodes['model'],
      // and Node.ChildNodes['number'] as needed...
    end;
  end;
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • How does that code then choose whether to pick the second or the first vehicle? – Shaun Roselt Jan 30 '17 at 09:14
  • 2
    @ShaunRoselt: the XML in the question was altered after I had posted this answer. This answer was written for different XML where the top-level element was the only `` element. Now the structure of the XML has been changed, so the code needs to be adjusted accordingly. I have updated my answer. – Remy Lebeau Jan 30 '17 at 20:44
  • 1
    @MarceloBergweiler seriously? It is time like this that I wish I could downvote comments. Drop a `TXMLDocument` into the Form and the `uses` clause is filled in automatically, like any other component. But whatever. I've updated my answer. – Remy Lebeau Jul 05 '19 at 16:14
6

You can read the XML file using the unit MSXML (or any other XML parser).

It gives you a tree structure representing the XML file. Where vehicle is the top node and the other three are the child nodes.

Each node has a text property that can be used to get the value. You can assign that to the text boxes on your form.

Code sample:

uses
  ActiveX,
  MSXML;

procedure TForm1.ReadFromXML(const AFilename: string);
var
  doc : IXMLDOMDocument;
  node : IXMLDomNode;

begin
  CoInitialize; // Needs to be called once before using CoDOMDocument.Create;
  if not FileExists(AFileName) then 
    Exit; // Add proper Error handling.

  doc := CoDOMDocument.Create;
  doc.load(AFileName);

  if (doc.documentElement = nil) or (doc.documentElement.nodeName <> 'vehicle') then
    Exit; // Add proper Error handling.

  node := doc.documentElement.firstChild;
  while node<>nil do begin
    if node.nodeName = 'model' then
      txtModel.Text := node.text;
    if node.nodeName = 'number' then
      txtNumber.Text := node.text;
    if node.nodeName = 'type' then
      txtType.Text := node.text;
    node := node.nextSibling;
  end;
end;
Toon Krijthe
  • 52,876
  • 38
  • 145
  • 202
  • 2
    Have a look at Delphi's own `TXMLDocument` wrapper component instead of accessing the `MSXML` engine directly. – Remy Lebeau Nov 11 '11 at 20:07
1

I wrote a library to manage XML files, it uses IXMLDocument interface to load the XML data from file or string, you can check it here.

To read multiple nodes you can do this:

uses
  .., IXMLData;

procedure TForm1.cxButton1Click(Sender: TObject);
var
  d : TIXMLDoc;
  i : integer;
begin
  d := TIXMLDoc.CreateFromFile('vehicle.xml');
  for i := 0 to d.childcount - 1 do
  begin
    //Here you get the different node values
    txtType.Text := d.Text(d.ChildNodes[i], 'type');
    txtModel.Text := d.Text(d.ChildNodes[i], 'model');
    txtType.Text :=d.Text(d.ChildNodes[i], 'number');
  end;
end;