John Barrat
John Barrat

Reputation: 840

How do I read this XML file

I need to read this XML file - extract below...

<device xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" dosid="03955" id="" name="PIC18F46Q84" rev="" xsi:noNamespaceSchemaLocation="PCG.xsd">
    <manager>

    <\manager>      
    <pins>
        <pin name="RE3" wpu="WPUE3" cn="RE3" inlvl="INLVLE3">
            <pinNumber package="46Q84" value="1"/>
            <pinNumber package="QFN40" value="16"/>
            <pinNumber package="TQFP44" value="18"/>
            <pinNumber package="QFN44" value="18"/>
            <pinAlias alias="VPP" module="RESET"/>
            <pinAlias alias="MCLR" module="RESET">
                <constraint name="configBit" type="lock">
                    <constraintVariable name="MCLRE" value="EXTMCLR"/>
                </constraint>
            </pinAlias>
            <pinAlias alias="RE3" module="GPIO"/>
        </pin>
        <pin ansel="ANSELA0" lat="LATA0" name="RA0" od="ODCA0" tris="TRISA0" pps="RA0" ppsValue="0x0" wpu="WPUA0" cn="RA0" slr="SLRA0" inlvl="INLVLA0">
            <pinNumber package="PDIP40" value="2"/>
            <pinNumber package="QFN40" value="17"/>
            <pinNumber package="TQFP44" value="19"/>
            <pinNumber package="QFN44" value="19"/>
            <pinAlias alias="ANA0" module="ADCC"/>
            <pinAlias alias="C1IN0-" module="CMP1"/>
            <pinAlias alias="C2IN0-" module="CMP2"/>
            <pinAlias alias="RA0" module="GPIO"/>
        </pin>
    </pins> 
<\device>

I have worked my way down to pins in a for next loop and to pin and to pinNumber (same method).
This is a really basic question, how do I read the items (pin name="RE3" wpu="WPUE3" cn="RE3" inlvl="INLVLE3") and similarly the childNodes and their items e.g. (pinNumber package="PDIP40" value="2"/)

I want to put the Package text into a Combobox, in this case it will be 4 deep. I want to create a class of Pin which will hold the PinNumber vs Package and the alises for the pin vs Module.

Pins will be a collection of type Pin

I have other tables to extract but if I can get advice on how to extract this basic data I am sure I will be able to continue from there.

Upvotes: 0

Views: 173

Answers (1)

fpiette
fpiette

Reputation: 12322

I wrote some code for you.

The code load the XML file you showed (By the way there are two backslashes where slashes should be) into a list of pins (Class TPins). Each pin is represented by a TPin class which contains the pin data, including two lists for pin number by package and pin alias (TPinNumbers list of TPinNumber and TPinAliases list of TPinAlias).

I made a method to load the XML file. Use is simple:

LoadXmlPins('SO67591149.xml');

Once loaded, you can do something like this:

for Pin in FPins do begin
    Memo1.Lines.Add(Pin.Name);
    Index := Pin.PinNumbers.FindIndexByPackage(Package);
    if Index >= 0 then
        Memo1.Lines.Add(' ' + Package +
                        ' Pin ' + Pin.PinNumbers[Index].Value);
end;

Here is the complete code, tested with Delphi 10.4.2:

unit XmlPinReaderDemoMain;

interface

uses
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
    System.Generics.Collections,
    Xml.XmlIntf, Xml.XmlDoc, Xml.xmldom;

type
    TPinNumber = class
        Package : String;
        Value   : String;
        class function LoadFromXml(NodePinNumber : IXmlNode) : TPinNumber;
    end;

    TPinNumbers = class(TObjectList<TPinNumber>)
       function FindIndexByPackage(const Package : String) : Integer;
    end;

    TPinAlias = class
        Alias  : String;
        Module : String;
        class function LoadFromXml(NodePinAlias : IXmlNode) : TPinAlias;
    end;

    TPinAliases = class(TObjectList<TPinAlias>)
    end;

    TPin = class
        Name     : String;
        Wpu      : String;
        Cn       : String;
        Inlvl    : String;
        Ansel    : String;
        Lat      : String;
        Od       : String;
        Tris     : String;
        Pps      : String;
        PpsValue : String;
        Slr      : String;
        PinNumbers : TPinNumbers;
        PinAliases : TPinAliases;
        constructor Create;
        destructor  Destroy; override;
        class function LoadFromXml(NodePin : IXmlNode) : TPin;
    end;

    TPins = class(TObjectList<TPin>)
        procedure LoadFromXml(NodePins : IXmlNode);
    end;


    TForm1 = class(TForm)
        Memo1: TMemo;
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
    private
        FPins : TPins;
    public
        constructor Create(AOwner : TComponent); override;
        destructor  Destroy; override;
        procedure LoadXmlPins(const FileName: String);
        procedure ShowResultDemo;
    end;

function XmlGetAttributeAsString(Node          : IXmlNode;
                                 const AttName : String) : String;

var
    Form1: TForm1;

implementation

{$R *.dfm}

// List all pin and pin number for package 'QFN40'
procedure TForm1.ShowResultDemo;
var
    Pin   : TPin;
    Index : Integer;
const
    Package = 'QFN40';
begin
    if FPins.Count = 0 then begin
        Memo1.Lines.Add('No pin found');
        Exit;
    end;
    for Pin in FPins do begin
        Memo1.Lines.Add(Pin.Name);
        Index := Pin.PinNumbers.FindIndexByPackage(Package);
        if Index >= 0 then
            Memo1.Lines.Add(' ' + Package +
                            ' Pin ' + Pin.PinNumbers[Index].Value);
    end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
    LoadXmlPins('SO67591149.xml');
    Memo1.Lines.Add('Loaded ' + IntToStr(FPins.Count) + ' pins');
    ShowResultDemo;
end;

procedure TForm1.LoadXmlPins(const FileName : String);
var
    XmlDoc       : IXMLDocument;
    NodeDevice   : IXMLNode;
    NodePins     : IXMLNode;
begin
    XmlDoc := TXMlDocument.Create(FileName);
    NodeDevice := XmlDoc.ChildNodes.FindNode('device');
    if not Assigned(NodeDevice) then begin
        Memo1.Lines.Add('Node ''device'' not found');
        exit;
    end;

    NodePins := NodeDevice.ChildNodes.FindNode('pins');
    if not Assigned(NodePins) then begin
        Memo1.Lines.Add('Node ''pins'' not found');
        exit;
    end;

    FPins.LoadFromXml(NodePins);
end;

constructor TForm1.Create(AOwner: TComponent);
begin
    inherited Create(AOwner);
    FPins := TPins.Create(TRUE);
end;

destructor TForm1.Destroy;
begin
    FreeAndNil(FPins);
    inherited Destroy;
end;

function XmlGetAttributeAsString(
    Node          : IXmlNode;
    const AttName : String) : String;
begin
    if Node.HasAttribute(AttName) then
        Result := Node.Attributes[AttName]
    else
        Result := '';
end;


{ TPin }

constructor TPin.Create;
begin
    inherited Create;
    PinNumbers := TPinNumbers.Create(TRUE);
    PinAliases := TPinAliases.Create(TRUE);
end;

destructor TPin.Destroy;
begin
    FreeAndNil(PinNumbers);
    FreeAndNil(PinAliases);
    inherited Destroy;
end;

class function TPin.LoadFromXml(NodePin: IXmlNode): TPin;
var
    I         : Integer;
    Node      : IXmlNode;
    PinNumber : TPinNumber;
    PinAlias  : TPinAlias;
begin
    if not Assigned(NodePin) then
        Result := nil
    else begin
        Result           := TPin.Create;
        Result.Name      := XmlGetAttributeAsString(NodePin, 'name');
        Result.Wpu       := XmlGetAttributeAsString(NodePin, 'wpu');
        Result.Cn        := XmlGetAttributeAsString(NodePin, 'cn');
        Result.Inlvl     := XmlGetAttributeAsString(NodePin, 'inlvl');
        Result.Ansel     := XmlGetAttributeAsString(NodePin, 'Ansel');
        Result.Lat       := XmlGetAttributeAsString(NodePin, 'Lat');
        Result.Od        := XmlGetAttributeAsString(NodePin, 'Od');
        Result.Tris      := XmlGetAttributeAsString(NodePin, 'Tris');
        Result.Pps       := XmlGetAttributeAsString(NodePin, 'Pps');
        Result.PpsValue  := XmlGetAttributeAsString(NodePin, 'PpsValue');
        Result.Slr       := XmlGetAttributeAsString(NodePin, 'Slr');
        for I := 0 to NodePin.ChildNodes.Count - 1 do begin
            Node := NodePin.ChildNodes.Get(I);
            if SameText(Node.NodeName, 'pinNumber') then begin
                PinNumber := TPinNumber.LoadFromXml(Node);
                if Assigned(PinNumber) then
                    Result.PinNumbers.Add(PinNumber);
            end
            else if SameText(Node.NodeName, 'pinAlias') then begin
                PinAlias := TPinAlias.LoadFromXml(Node);
                if Assigned(PinAlias) then
                    Result.PinAliases.Add(PinAlias);
            end;
        end;
    end;
end;

{ TPinNumber }

class function TPinNumber.LoadFromXml(NodePinNumber: IXmlNode): TPinNumber;
begin
    if not Assigned(NodePinNumber) then
        Result := nil
    else begin
        Result := TPinNumber.Create;
        Result.Package := XmlGetAttributeAsString(NodePinNumber, 'package');
        Result.Value   := XmlGetAttributeAsString(NodePinNumber, 'value');
    end;
end;

{ TPinAlias }

class function TPinAlias.LoadFromXml(NodePinAlias: IXmlNode): TPinAlias;
begin
    if not Assigned(NodePinAlias) then
        Result := nil
    else begin
        Result := TPinAlias.Create;
        Result.Alias  := XmlGetAttributeAsString(NodePinAlias, 'alias');
        Result.Module := XmlGetAttributeAsString(NodePinAlias, 'module');
    end;
end;

{ TPins }

procedure TPins.LoadFromXml(NodePins: IXmlNode);
var
    I       : Integer;
    NodePin : IXmlNode;
    Pin     : TPin;
begin
    Clear;
    for I := 0 to NodePins.ChildNodes.Count - 1 do begin
        NodePin := NodePins.ChildNodes.Get(I);
        Pin     := TPin.LoadFromXml(NodePin);
        if Assigned(Pin) then
            Add(Pin);
    end;
end;

{ TPinNumbers }

function TPinNumbers.FindIndexByPackage(const Package: String): Integer;
var
    Index : Integer;
begin
    for Index := 0 to Count - 1 do begin
        if SameText(Package, Items[Index].Package) then begin
            Result := Index;
            Exit;
        end;
    end;
    Result := -1;
end;

end.

I coded minimum validity checks. You should probably add more if you want to support possibly bad XML file.

Upvotes: 1

Related Questions