Delphi free XML parser / Reader for GPX files

落爺英雄遲暮 提交于 2019-12-22 18:33:27

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!