问题
I am looking for a free easy to use XML parser / Reader for GPX files in Delphi and was wondering if anyone could recommend one or should i be using Delphi's own XML data binding / XML document?
thanks
Colin
回答1:
You can use the Tool "XML mapper" of Delphi.
Here on my blog, you can find the article "Load an GPX file (XML) y acces to data" that explain how use this tool (XML Mapper). The sample create structure to load GPX Files.
You can find other similar post, like this "Generate KML files routes; Tracks on Google Maps" that use this tools also to generate KML files.
The webpage is originaly in Spanish, but you can use Google translate (on right of page). Also you can download the source code of samples and see/test it.
Regards.
回答2:
NativeXml
This is a small-footprint native Delphi implementation to read and write XML documents. It provides a fully object-oriented approach to working with XML files, with clearly defined and Delphi-focused properties, events and methods.
You can use this code to read and write XML documents from/to files, streams or strings. The load routine generates events that can be used to display load progress on the fly.
NativeXML Website
回答3:
OmniXML
It is free (MPL 1.1), reasonably fast and implements the DOM Level 1 spec plus some MS extensions.
There are some OmniXML examples on the StackOverflow.
回答4:
Alternate way with TNativeXML.
You can obviously derive specialized class from TNativeXml but in my code I used a helper class :
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.
A practical sample using the uHelper unit :
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.
回答5:
You can use SimpleStorage.
Sample code accessing Gpx file :
interface
uses
...
Cromis.SimpleStorage, ...
type
TMainForm = class(TForm)
...
MmGpx: TMemo;
BtnLoad: TButton;
OpenDialog: TOpenDialog;
...
private
FGpxStorage: ISimpleStorage;
protected
procedure ShowGpx;
end;
...
implementation
procedure TMainForm.BtnLoadClick(Sender: TObject);
begin
if OpenDialog.Execute then
FGpxStorage := StorageFromFile(OpenDialog.FileName); // <<<
ShowGpx;
end;
end;
procedure TMainForm.ShowGpx;
begin
MmGpx.Lines.Text := FGpxStorage.Content(True); // <<<
end;
Moreover, you can still find here a template of using SimpleStorage to generate compliant new Gpx file from scratch.
来源:https://stackoverflow.com/questions/8354069/delphi-free-xml-parser-reader-for-gpx-files