3
votes

Firstly, I'm new to coding and Delphi, been on and off with it for a few months.

Below is a sample xml file.

What I'm trying to achieve is to Parse all data in each 'Name' section of the .xml file.

I have never done this before. Some guidance would be appreciated. I have looked at other questions on here similar to this but I cant quite get to grips with it.

I have no code example to provide....this is how stuck I am, I do not know where to begin.

<ds>
<Customers>
<Name>
<address_name>test 1</address_name> 
<address_line_1>test 1</address_line_1> 
<address_line_2>test 1</address_line_2> 
<address_line_3>test 1</address_line_3>
<postcode>test 1</postcode> 
<tel_no>test 1</tel_no> 
<fax_no>test 1</fax_no> 
<email_address>test 1<email_address/> 
<website>test 1<website /> 
</Name>
<Name>
<address_name>test 2</address_name> 
<address_line_1>test 2</address_line_1> 
<address_line_2>test 2</address_line_2> 
<address_line_3>test 2</address_line_3>
<postcode>test 2</postcode> 
<tel_no>test 2</tel_no> 
<fax_no>test 2</fax_no> 
<email_address>test 2<email_address/> 
<website>test 2<website /> 
</Name>
<Name>
<address_name>test 3</address_name> 
<address_line_1>test 3</address_line_1> 
<address_line_2>test 3</address_line_2> 
<address_line_3>test 3</address_line_3>
<postcode>test 3</postcode> 
<tel_no>test 3</tel_no> 
<fax_no>test 3</fax_no> 
<email_address>test 3<email_address/> 
<website>test 3<website /> 
</Name>
<Customers>
</ds>

Thanks,

4
I'll post an answer to show you one way to do this in a few minutes. Meanwhile, you have some errors in your xml. The closing tags of the email_address and website nodes should have their closing slashes at their starts, not their ends, and the final <customers> should be </customers>.MartynA
Only just noticed that, sorry I don't know why I wrote them like that.Sharpie
Then edit your post to fix it, and next time post valid XML instead of something you just typed into your question. If it's not worth your time to post valid data or code, why should it be worth ours to try to solve your problem?Ken White

4 Answers

9
votes

A better aproach for your xml file would be:

<ds>
    <Customers>
        <Customer>
            <address_name>test 1</address_name> 
            <address_line_1>test 1</address_line_1> 
            <address_line_2>test 1</address_line_2> 
            <address_line_3>test 1</address_line_3>
            <postcode>test 1</postcode> 
            <tel_no>test 1</tel_no> 
            <fax_no>test 1</fax_no> 
            <email_address>test 1</email_address> 
            <website>test 1</website> 
        </Customer>
        <Customer>
            <address_name>test 2</address_name> 
            <address_line_1>test 2</address_line_1> 
            <address_line_2>test 2</address_line_2> 
            <address_line_3>test 2</address_line_3>
            <postcode>test 2</postcode> 
            <tel_no>test 2</tel_no> 
            <fax_no>test 2</fax_no> 
            <email_address>test 2</email_address> 
            <website>test 2</website> 
        </Customer>
        <Customer>
            <address_name>test 3</address_name> 
            <address_line_1>test 3</address_line_1> 
            <address_line_2>test 3</address_line_2> 
            <address_line_3>test 3</address_line_3>
            <postcode>test 3</postcode> 
            <tel_no>test 3</tel_no> 
            <fax_no>test 3</fax_no> 
            <email_address>test 3</email_address> 
            <website>test 3</website> 
        </Customer>
    </Customers>
</ds>

To read this file:

Insert this two uses: XMLDoc, XMLIntf;

Here is a procedure to read your XML file.

procedure TForm1.btnReadXmlFileClick(Sender: TObject);
var
  XmlFile : TXMLDocument;
  MainNode, CustomerNode : IXMLNode;
  i : Integer;
  XMLPath : string;
begin
  XMLPath := 'Z:\Temp\xmlToRead.xml'; //example of path
  XmlFile :=  TXMLDocument.Create(Application);
  try
    XmlFile.LoadFromFile(XMLPath);
    XmlFile.Active := True;
    MainNode := XmlFile.DocumentElement;

    for i:=0 to MainNode.ChildNodes['Customers'].ChildNodes.Count-1 do
    begin
      CustomerNode := MainNode.ChildNodes['Customers'].ChildNodes[i];
      //Here you can get any imformation
      ShowMessage(CustomerNode.ChildNodes['address_name'].Text);
      ShowMessage(CustomerNode.ChildNodes['address_line_1'].Text);
    end;
  finally
    FreeAndNil(XmlFile);
  end;
end;
4
votes

Depending on your Delphi SKU, you can do this using Delphi components very easily if it comes with the XMLMapper utility (in Delphi's Bin directory).

Create a new project containing

  • a TClientDataSet
  • a TDatasource
  • a TDbGrid

Connect the datasource to the CDS and the grid to the datasource;

  • add an XMLTransformerProvider

Set the ProviderName of the CDS to the name of the XMLTransformerProvider

In the FormCreate event, open the CDS.

Save the project.

Then, after correcting your XML file as I mentioned in my comment, load it into Delphi's XMLMapper.

In XML Mapper,

  • Select the DocumentView tab of the LH, Document pane

  • Double-click each of the nodes address_name .. website in turn

  • Click Create | DataPacket from XML in the menu

  • Click the Create and Test Transformation button on the Mapping tab of the central, Transformation pane.

  • From the menu, go to File | Save | Transformation and save your .Xtr file.

Back in your Delphi project, point the XMLDataFile property of the XMLTransformProvider at your XML file, & the TransformationFile of its TransformRead zub-component at your .Xtr file.

Compile & run your project.

The TFields created in your CDS have types and sizes determined by the .Xtr file generated by XMLMapper. You can fine-tune these as follows:

In XMLMapper:

  • Select the Node Properties tab of the Transformation pane.

  • In the Document View tab of the Document pane, click one of the data nodes-

  • You can then set its Data Type and Max Length on the Node Propertyies tab.

1
votes

If the XML is structured similar to a single, flat dataset, you can create Dephi wrapper including reader and writer classes with XML Schema Binding Wizard (included in Delphi Professional).

The basic steps are

  • create a XSD file which represents the XML structure
  • run the XML Schema Binding Wizard

The first step can be done manually, maybe there are also tools which generate a XSD for you based on a sample XML. But for your XML it seems rather easy to write the XSD yourself.

Delphi generates a easy to use set of classes which can be used to read, modify, and write the XML document.

1
votes

Your XML is invalid (as well as having a terrible structure), but here's an example of some (valid) XML with a similar schema that might help you, using a straight IXMLDocument approach to populate a memo with a list of persons.

uses
  XMLIntf, XMLDoc;

const
  TestXML = '<?xml version="1.0"?>' +
            '<customers>' +
            '<people>' +
            '<person>' +
            '<name>John Smith</name>' +
            '<address>123 Main Street</address>'+
            '<city>Sometown</city>' +
            '<state>NY</state>' +
            '<zip>12345</zip>' +
            '</person>' +
            '<person>' +
            '<name>Jane Doe</name>' +
            '<address>456 Scenic View Blvd</address>'+
            '<city>Richtown</city>' +
            '<state>CT</state>' +
            '<zip>23456</zip>' +
            '</person>' +
            '</people>' +
            '</customers>';


procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Clear;
  ParseXMLToMemo;
end;

procedure TForm1.ParseXMLToMemo;
var
  Doc: IXMLDocument;
  Root: IXMLNode;
  PersonList: IXMLNodeList;
  Person: IXMLNode;
  i: Integer;
begin
  Doc := LoadXMLData(TestXML);
  Doc.Active := True;
  Root := Doc.DocumentElement;  // Get <people>
  PersonList := Root.ChildNodes['people'].ChildNodes;
  Person := PersonList.First;
  while Assigned(Person) do
  begin
    Memo1.Lines.Add(Person.ChildValues['name']);
    Memo1.Lines.Add(Person.ChildValues['address']);
    Memo1.Lines.Add(Person.ChildValues['city']);
    Memo1.Lines.Add(Person.ChildValues['state']);
    Memo1.Lines.Add(Person.ChildValues['zip']);
    Person := Person.NextSibling;
  end;
end;