Альтернативный способ с TNativeXML .
Очевидно, что вы можете получить специализированный класс из TNativeXml, но в моем коде я использовал вспомогательный класс:
unit uHelper;
interface
uses
SysUtils,
Classes,
NativeXml;
const
// Do not localize these
sNamespace = 'http://www.topografix.com/GPX/1/1';
sVersion = '1.1';
sCreator = 'SwathGen';
sSchemaInstance = 'http://www.w3.org/2001/XMLSchema-instance';
sSchemaLocation = sNamespace+' '+
'http://www.topografix.com/GPX/1/1/gpx.xsd';
resourcestring
sNoGpxRoot = '<%s> has no gpx root !';
sWrongGpxXmlns = '<%s> root has a wrong xmlns attribute';
sWrongGpxVersion = '<%s> is not a version "1.1" gpx file !';
type
EGpxException = class(Exception)
end;
type
TGpxHelper = class helper for TNativeXml
private
function GetMetadataNode: TXmlNode;
function GetWaypointNodes: TsdNodeList;
function GetRouteNodes: TsdNodeList;
function GetTrackNodes: TsdNodeList;
function GetExtensionsNode: TXmlNode;
public
constructor CreateGpx(AOwner: TComponent);
procedure NewGpx;
procedure NodesAdd(ANodes: array of TXmlNode); overload;
procedure AssignToStrings(AStrings:TStrings);
function Element(const AName: string): TXmlNode;
// File IO
procedure LoadGpxFromFile(const AFileName: string);
procedure SaveGpxToFile(const AFileName: string);
property Metadata:TXmlNode read GetMetadataNode;
property Waypoints:TsdNodeList read GetWaypointNodes;
property Routes:TsdNodeList read GetRouteNodes;
property Tracks:TsdNodeList read GetTrackNodes;
property Extensions:TXmlNode read GetExtensionsNode;
end;
TGpxNodeHelper = class helper for TXmlNode
function Element(const AName: string): TXmlNode;
end;
implementation
{ TGpxHelper }
procedure TGpxHelper.AssignToStrings(AStrings:TStrings);
var
lXmlFormat: TXmlFormatType;
lIndentString: string;
begin
// Save states
lXmlFormat := XmlFormat;
lIndentString := IndentString;
XmlFormat := xfReadable;
IndentString := ' ';
AStrings.Text := WriteToString;
// Restore states
XmlFormat := lXmlFormat;
IndentString := lIndentString;
end;
constructor TGpxHelper.CreateGpx(AOwner: TComponent);
begin
inherited Create(AOwner);
//
NewGpx;
end;
function TGpxHelper.Element(const AName: string): TXmlNode;
begin
Result := Root.Element(AName);
end;
function TGpxHelper.GetExtensionsNode: TXmlNode;
begin
Result := Element('extensions');
end;
function TGpxHelper.GetMetadataNode: TXmlNode;
begin
Result := Element('metadata');
end;
function TGpxHelper.GetRouteNodes: TsdNodeList;
begin
Result := TsdNodeList.Create(False);
Root.NodesByName('rte', Result);
end;
function TGpxHelper.GetTrackNodes: TsdNodeList;
begin
Result := TsdNodeList.Create(False);
Root.NodesByName('trk', Result);
end;
function TGpxHelper.GetWaypointNodes: TsdNodeList;
begin
Result := TsdNodeList.Create(False);
Root.NodesByName('wpt', Result);
end;
procedure TGpxHelper.LoadGpxFromFile(const AFileName: string);
var
lGpx: TNativeXml;
lFileName: TFileName;
begin
lFileName := ExtractFileName(AFileName);
lGpx := TNativeXml.Create(Self);
lGpx.LoadFromFile(AFileName);
try
if lGpx.Root.Name<>'gpx' then
raise EGpxException.CreateFmt(sNoGpxRoot,[lFileName])
else if lGpx.Root.AttributeValue[Root.AttributeIndexByName('xmlns')]<>sNamespace then
raise EGpxException.CreateFmt(sWrongGpxXmlns,[lFileName])
else if lGpx.Root.AttributeValue[Root.AttributeIndexByName('version')]<>sVersion then
raise EGpxException.CreateFmt(sWrongGpxVersion,[lFileName])
else
Self.ReadFromString(lGpx.WriteToString) // <<<
finally
lGpx.Free
end;
end;
procedure TGpxHelper.NewGpx;
begin
New;
Root.Name := 'gpx';
NodesAdd(
[
AttrText('xmlns', sNamespace),
AttrText('version', sVersion),
AttrText('creator', sCreator),
AttrText('xmlns:xsi',sSchemaInstance),
AttrText('xsi:schemaLocation', sSchemaLocation),
// Metadata
NodeNew('metadata',
[
NodeNewAttr('bounds',
[
AttrText('minlat','90.00000000'),
AttrText('minlon','180.00000000'),
AttrText('maxlat','-90.00000000'),
AttrText('maxlon','-180.00000000')
]
),
NodeNew('extensions')
]
),
// Waypoints
// Routes
// Tracks
NodeNew('extensions')
]
);
end;
procedure TGpxHelper.NodesAdd(ANodes: array of TXmlNode);
begin
Root.NodesAdd(ANodes);
end;
procedure TGpxHelper.SaveGpxToFile(const AFileName: string);
begin
ChangeFileExt(AFileName,'gpx');
SaveToFile(AFileName);
end;
{ TGpxNodeHelper }
function TGpxNodeHelper.Element(const AName: string): TXmlNode;
begin
Result := NodeByName(UTF8String(AName));
end;
end.
Практический образец с использованием устройства uHelper:
unit ufrmMain;
interface
uses
NativeXml,
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, SynEdit, SynMemo, SynEditHighlighter, SynHighlighterXML,
SynEditMiscClasses, SynEditSearch, ComCtrls;
type
TMainForm = class(TForm)
BtnNew: TButton;
BtnLoad: TButton;
OpenDialog: TOpenDialog;
BtnSave: TButton;
SaveDialog: TSaveDialog;
Memo: TSynMemo;
XMLSyn: TSynXMLSyn;
Search: TSynEditSearch;
StatusBar: TStatusBar;
procedure FormCreate(Sender: TObject);
procedure BtnLoadClick(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure BtnSaveClick(Sender: TObject);
procedure BtnNewClick(Sender: TObject);
private
FGpx: TNativeXml;
procedure ShowGpxInfo;
procedure UpdateControls;
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
uses
Math,
uHelper;
{$R *.dfm}
procedure TMainForm.BtnLoadClick(Sender: TObject);
begin
OpenDialog.FileName := '';
if OpenDialog.Execute then
begin
FGpx.LoadGpxFromFile(OpenDialog.FileName);
UpdateControls;
ShowGpxInfo
end;
end;
procedure TMainForm.BtnNewClick(Sender: TObject);
begin
FGpx.NewGpx;
UpdateControls;
end;
procedure TMainForm.BtnSaveClick(Sender: TObject);
begin
SaveDialog.FileName := '';
if SaveDialog.Execute then
begin
FGpx.SaveGpxToFile(SaveDialog.FileName);
end;
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
FGpx := TNativeXml.CreateGpx(Self);
end;
procedure TMainForm.FormShow(Sender: TObject);
begin
UpdateControls;
end;
procedure TMainForm.ShowGpxInfo;
const
cLF = #10#13;
cMsg = 'metadata node count : %u'+cLF+
'wpt node count : %u'+cLF+
'rte node count : %u'+cLF+
'trk node count : %u'+cLF+
'extensions node count : %u';
var
lMetadataCount: Integer;
lWaypointsCount: Integer;
lRoutesCount: Integer;
lTracksCount: Integer;
lExtensions: Integer;
begin
lMetadataCount := IfThen(Assigned(FGpx.Metadata),1,0);
with FGpx.Waypoints do
try
lWaypointsCount := Count;
finally
Free
end;
with FGpx.Routes do
try
lRoutesCount := Count;
finally
Free
end;
with FGpx.Tracks do
try
lTracksCount := Count;
finally
Free
end;
lExtensions := IfThen(Assigned(FGpx.Extensions),1,0);
ShowMessage(Format(cMsg,[lMetadataCount,lWaypointsCount,lRoutesCount,lTracksCount,lExtensions]))
end;
procedure TMainForm.UpdateControls;
begin
FGpx.AssignToStrings(Memo.Lines); // <<<
end;
end.