Reputation: 840
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
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