Quel Est L'analyseur XML le plus rapide Disponible pour Delphi?

nous avons des chaînes XML assez grandes que nous analysons actuellement en utilisant MSXML2

je viens d'essayer D'utiliser MSXML6 en espérant une amélioration de la vitesse et je n'ai rien obtenu!

nous créons actuellement beaucoup de documents DOM et je suppose qu'il peut y avoir des frais généraux dans l'interaction constante avec la dll MSXML2/6

est-ce que quelqu'un connaît un composant XML meilleur/plus rapide pour Delphi?

si quelqu'un peut suggérer une alternative, et c'est plus rapide, nous chercherons pour l'intégrer, mais ce serait beaucoup de travail, donc espérons que la structure ne serait pas trop différente de celle utilisée par MSXML

nous utilisons Delphi 2010

Paul

30
demandé sur Paul 2012-02-28 23:43:14

5 réponses

récemment, j'ai eu un problème similaire où l'utilisation du DOM parser MSXML s'est avérée trop lente pour la tâche donnée. J'ai dû analyser des documents assez grands > 1MB et la consommation de mémoire du DOM parser était prohibitive. Ma solution était de ne pas utiliser un DOM parser du tout, mais d'aller avec le MSXML Sax parser. Cela s'est avéré être beaucoup, beaucoup plus rapide. Malheureusement le modèle de programmation est totalement différent, mais dépendant de la tâche, il pourrait en valoir la peine. Craig Murphy a publié un excellent article sur la façon d'utiliser L'analyseur de SAX MSXML à delphi: SAX, Delphi et Ex Em El

11
répondu Lars Frische 2012-02-29 08:04:27

il y a quelque temps j'ai dû sérialiser record au format XML; pour ex:

 TTest = record
    a : integer;
    b : real; 
 end;

pour

    <Data>
        <a type="tkInteger">value</a>
        <b type="tkFloat">value</b>
    </Data>

J'ai utilisé RTTI pour naviguer récursivement dans les champs d'enregistrement et stocker des valeurs en XML. J'ai essayé quelques analyseurs XML. Je n'avais pas besoin de DOM model pour créer xml, mais j'en avais besoin pour le charger.

XML figurant sur 310k noeuds (10-15moctets); résultats présentés dans le tableau ci-dessous, il y a 6 colonnes avec le temps en secondes;

Un - il est temps de créer des noeuds et d'écrire des valeurs

2-SaveToFile ();

3 = 1 + 2

4-LoadFromFile ();

5-naviguer à travers les noeuds et lire les valeurs

6 = 4 + 5

enter image description here

MSXML/Xerces/ADOM - sont des vendeurs différents pour TXMLDocument (DOMVendor)

JanXML ne fonctionne pas avec unicode; j'ai corrigé quelques erreurs, et j'ai sauvegardé XML, mais le chargement provoque AV (ou un débordement de la pile, Je ne rappelez-vous);

manual - signifie écrire manuellement XML en utilisant TStringStream.

j'ai utilisé Delphi2010, Win7x32, Q8200 CPU / 2,3 GHz, 4 Go de RAM.

mise à jour: vous pouvez télécharger le code source pour ce test (enregistrer la sérialisation en XML en utilisant RTTI) icihttp://blog.karelia.pro/teran/files/2012/03/XMLTest.zip tous les analyseurs (Omni, natif, Jan) sont inclus (maintenant le nombre de noeuds en XML est d'environ 270k), désolé il n'y a pas de commentaires dans le code.

34
répondu teran 2012-03-01 07:50:23

je sais que c'est une vieille question, mais les gens peuvent trouver intéressant:

j'ai écrit une nouvelle bibliothèque XML pour Delphi (OXml):http://www.kluug.net/oxml.php

il est doté d'une gestion XML directe (lecture+écriture), d'un analyseur SAX, D'un DOM et d'un analyseur DOM séquentiel. Un des avantages est Qu'OXml supporte Delphi 6-Delphi XE5, FPC/Lazarus et C++Builder sur toutes les plateformes (Win, MacOSX, Linux, iOS, Android).

OXml DOM est basé sur un enregistrement / pointeur et offre de meilleures performances que n'importe quelle autre bibliothèque XML:

le test de lecture renvoie le temps dont l'analyseur a besoin pour lire un DOM XML personnalisé à partir d'un fichier (colonne "charge") et pour écrire des valeurs de noeud à une fonction factice constante (colonne "naviguer"). Le fichier est encodé en UTF-8 et sa taille est d'environ 5,6 Mo.

XML parse comparison

Le test d'écriture renvoie le temps dont l'analyseur a besoin pour créer un DOM (colonne "créer") et écrire ce DOM pour un fichier (colonne "enregistrer"). Le fichier est encodé en UTF-8 et sa taille est d'environ 11 Mo.

XML write comparison

+ la piètre performance D'écriture D'OmniXML (original) était le résultat du fait Qu'OmniXML n'utilisait pas de tampon pour écrire. Ainsi, écrire à un TFileStream était très lent. J'ai mis à jour OmniXML et ajouté le support de buffering. Vous pouvez obtenir le dernier code OmniXML à partir du SVN.

22
répondu oxo 2014-02-11 20:58:04

un jour, j'ai écrit une suite de test XML très simple. Il sert MSXML (D7 MSXML3?), Omni XML (bit old) et Jedi XML (Last stable).

résultats de Test pour 1,52 MO fichier:

fichier XML de temps de chargement MSXML: 240,20 [ms]

nœud XML sélections MSXML: 1,09 [s]

fichier XML de temps de chargement OmniXML: 2,25 [s]

nœud XML sélections OmniXML: 1,22 [s]

temps de chargement du fichier XML JclSimpleXML: 2,11 [s]

et violation de l'accès pour les sélections de noeuds JclSimpleXML:/

malheureusement je n'ai pas beaucoup de temps pour corriger au-dessus de AV, mais les sorces sont contenues ci-dessous...

fmuMain.pas

program XmlEngines;

uses
  FastMM4,
  Forms,
  fmuMain in 'fmuMain.pas' {fmMain},
  uXmlEngines in 'uXmlEngines.pas',
  ifcXmlEngine in 'ifcXmlEngine.pas';

{$R *.res}

begin
  Application.Initialize;
  Application.Title := 'XML Engine Tester';
  Application.CreateForm(TfmMain, fmMain);
  Application.Run;
end.

fmuMain.pas

unit fmuMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, xmldom, XMLIntf, msxmldom, XMLDoc,
  //
  ifcXmlEngine, StdCtrls;

type
  TfmMain = class(TForm)
    mmoDebug: TMemo;
    dlgOpen: TOpenDialog;

    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);

    procedure mmoDebugClick(Sender: TObject);

  private
    fXmlEngines: TInterfaceList;
    function Get_Engine(const aIx: Integer): IXmlEngine;

  protected
    property XmlEngine[const aIx: Integer]: IXmlEngine read Get_Engine;

    procedure Debug(const aInfo: string); // inline

  public
    procedure RegisterXmlEngine(const aEngine: IXmlEngine);

  end;

var
  fmMain: TfmMain;

implementation

{$R *.dfm}

uses
  uXmlEngines, TZTools;

{ TForm1 }

function TfmMain.Get_Engine(const aIx: Integer): IXmlEngine;
begin
  Result:= nil;
  Supports(fXmlEngines[aIx], IXmlEngine, Result)
end;

procedure TfmMain.RegisterXmlEngine(const aEngine: IXmlEngine);
var
  Ix: Integer;
begin
  if aEngine = nil then
    Exit; // WARRNING: program flow disorder

  for Ix:= 0 to Pred(fXmlEngines.Count) do
    if XmlEngine[Ix] = aEngine then
      Exit; // WARRNING: program flow disorder

  fXmlEngines.Add(aEngine)
end;

procedure TfmMain.FormCreate(Sender: TObject);
begin
  fXmlEngines:= TInterfaceList.Create();
  dlgOpen.InitialDir:= ExtractFileDir(ParamStr(0));
  RegisterXmlEngine(TMsxmlEngine.Create(Self));
  RegisterXmlEngine(TOmniXmlEngine.Create());
  RegisterXmlEngine(TJediXmlEngine.Create());
end;

procedure TfmMain.mmoDebugClick(Sender: TObject);

  procedure TestEngines(const aFilename: TFileName);

    procedure TestEngine(const aEngine: IXmlEngine);
    var
      PerfCheck: TPerfCheck;
      Ix: Integer;
    begin
      PerfCheck := TPerfCheck.Create();
      try

        PerfCheck.Init(True);
        PerfCheck.Start();
        aEngine.Load(aFilename);
        PerfCheck.Pause();
        Debug(Format(
          'XML file loading time %s: %s',
          [aEngine.Get_ID(), PerfCheck.TimeStr()]));

        if aEngine.Get_ValidNode() then
        begin
          PerfCheck.Start();
          for Ix:= 0 to 999999 do
            if aEngine.Get_ChildsCount() > 0 then
            begin

              aEngine.SelectChild(Ix mod aEngine.Get_ChildsCount());

            end
            else
              aEngine.SelectRootNode();

          PerfCheck.Pause();
          Debug(Format(
            'XML nodes selections %s: %s',
            [aEngine.Get_ID(), PerfCheck.TimeStr()]));
        end

      finally
        PerfCheck.Free();
      end
    end;

  var
    Ix: Integer;
  begin
    Debug(aFilename);
    for Ix:= 0 to Pred(fXmlEngines.Count) do
      TestEngine(XmlEngine[Ix])
  end;

var
  CursorBckp: TCursor;
begin
  if dlgOpen.Execute() then
  begin

    CursorBckp:= Cursor;
    Self.Cursor:= crHourGlass;
    mmoDebug.Cursor:= crHourGlass;
    try
      TestEngines(dlgOpen.FileName)
    finally
      Self.Cursor:= CursorBckp;
      mmoDebug.Cursor:= CursorBckp;
    end

  end
end;

procedure TfmMain.Debug(const aInfo: string);
begin
  mmoDebug.Lines.Add(aInfo)
end;

procedure TfmMain.FormDestroy(Sender: TObject);
begin
  fXmlEngines.Free()
end;

end.

ifcXmlEngine.pas

unit ifcXmlEngine;

interface

uses
  SysUtils;

type
  TFileName = SysUtils.TFileName;

  IXmlEngine = interface
    ['{AF77333B-9873-4FDE-A3B1-260C7A4D3357}']
    procedure Load(const aFilename: TFileName);
    procedure SelectRootNode();
    procedure SelectChild(const aIndex: Integer);
    procedure SelectParent();
    //
    function Get_ID(): string;
    function Get_ValidNode(): Boolean;
    function Get_ChildsCount(): Integer;
    function Get_HaveParent(): Boolean;
    //function Get_NodeName(): Boolean;
  end;

implementation

end.

uXmlEngines.pas

unit uXmlEngines;

interface

uses
  Classes,
  //
  XMLDoc, XMLIntf, OmniXml, JclSimpleXml,
  //
  ifcXmlEngine;

type
  TMsxmlEngine = class(TInterfacedObject, IXmlEngine)
  private
    fXmlDoc: XMLDoc.TXMLDocument;
    fNode: XMLIntf.IXMLNode;

  protected

  public
    constructor Create(const aOwner: TComponent);
    destructor Destroy; override;

    procedure Load(const aFilename: TFileName);
    procedure SelectRootNode();
    procedure SelectChild(const aIndex: Integer);
    procedure SelectParent();
    //
    function Get_ID(): string;
    function Get_ValidNode(): Boolean;
    function Get_ChildsCount(): Integer;
    function Get_HaveParent(): Boolean;
    //function Get_NodeName(): Boolean;

  end;

  TOmniXmlEngine = class(TInterfacedObject, IXmlEngine)
  private
    fXmlDoc: OmniXml.IXmlDocument;
    fNode: OmniXml.IXMLNode;

  protected

  public
    constructor Create;
    destructor Destroy; override;

    procedure Load(const aFilename: TFileName);
    procedure SelectRootNode();
    procedure SelectChild(const aIndex: Integer);
    procedure SelectParent();
    //
    function Get_ID(): string;
    function Get_ValidNode(): Boolean;
    function Get_ChildsCount(): Integer;
    function Get_HaveParent(): Boolean;
    //function Get_NodeName(): Boolean;

  end;

  TJediXmlEngine = class(TInterfacedObject, IXmlEngine)
  private
    fXmlDoc: TJclSimpleXML;
    fNode: TJclSimpleXMLElem;

  protected

  public
    constructor Create();
    destructor Destroy(); override;

    procedure Load(const aFilename: TFileName);
    procedure SelectRootNode();
    procedure SelectChild(const aIndex: Integer);
    procedure SelectParent();
    //
    function Get_ID(): string;
    function Get_ValidNode(): Boolean;
    function Get_ChildsCount(): Integer;
    function Get_HaveParent(): Boolean;
    //function Get_NodeName(): Boolean;

  end;

implementation

uses
  SysUtils;

{ TMsxmlEngine }

constructor TMsxmlEngine.Create(const aOwner: TComponent);
begin
  if aOwner = nil then
    raise Exception.Create('TMsxmlEngine.Create() -> invalid owner');

  inherited Create();
  fXmlDoc:= XmlDoc.TXmlDocument.Create(aOwner);
  fXmlDoc.ParseOptions:= [poPreserveWhiteSpace]
end;

destructor TMsxmlEngine.Destroy;
begin
  fXmlDoc.Free();
  inherited Destroy()
end;

function TMsxmlEngine.Get_ChildsCount: Integer;
begin
  Result:= fNode.ChildNodes.Count
end;

function TMsxmlEngine.Get_HaveParent: Boolean;
begin
  Result:= fNode.ParentNode <> nil
end;

function TMsxmlEngine.Get_ID: string;
begin
  Result:= 'MSXML'
end;

//function TMsxmlEngine.Get_NodeName: Boolean;
//begin
//  Result:= fNode.Text
//end;

function TMsxmlEngine.Get_ValidNode: Boolean;
begin
  Result:= fNode <> nil
end;

procedure TMsxmlEngine.Load(const aFilename: TFileName);
begin
  fXmlDoc.LoadFromFile(aFilename);
  SelectRootNode()
end;

procedure TMsxmlEngine.SelectChild(const aIndex: Integer);
begin
  fNode:= fNode.ChildNodes.Get(aIndex)
end;

procedure TMsxmlEngine.SelectParent;
begin
  fNode:= fNode.ParentNode
end;

procedure TMsxmlEngine.SelectRootNode;
begin
  fNode:= fXmlDoc.DocumentElement
end;

{ TOmniXmlEngine }

constructor TOmniXmlEngine.Create;
begin
  inherited Create();
  fXmlDoc:= OmniXml.TXMLDocument.Create();
  fXmlDoc.PreserveWhiteSpace:= true
end;

destructor TOmniXmlEngine.Destroy;
begin
  fXmlDoc:= nil;
  inherited Destroy()
end;

function TOmniXmlEngine.Get_ChildsCount: Integer;
begin
  Result:= fNode.ChildNodes.Length
end;

function TOmniXmlEngine.Get_HaveParent: Boolean;
begin
  Result:= fNode.ParentNode <> nil
end;

function TOmniXmlEngine.Get_ID: string;
begin
  Result:= 'OmniXML'
end;

//function TOmniXmlEngine.Get_NodeName: Boolean;
//begin
//  Result:= fNode.NodeName
//end;

function TOmniXmlEngine.Get_ValidNode: Boolean;
begin
  Result:= fNode <> nil
end;

procedure TOmniXmlEngine.Load(const aFilename: TFileName);
begin
  fXmlDoc.Load(aFilename);
  SelectRootNode()
end;

procedure TOmniXmlEngine.SelectChild(const aIndex: Integer);
begin
  fNode:= fNode.ChildNodes.Item[aIndex]
end;

procedure TOmniXmlEngine.SelectParent;
begin
  fNode:= fNode.ParentNode
end;

procedure TOmniXmlEngine.SelectRootNode;
begin
  fNode:= fXmlDoc.DocumentElement
end;

{ TJediXmlEngine }

constructor TJediXmlEngine.Create;
begin
  inherited Create();
  fXmlDoc:= TJclSimpleXML.Create();
end;

destructor TJediXmlEngine.Destroy;
begin
  fXmlDoc.Free();
  inherited Destroy()
end;

function TJediXmlEngine.Get_ChildsCount: Integer;
begin
  Result:= fNode.ChildsCount
end;

function TJediXmlEngine.Get_HaveParent: Boolean;
begin
  Result:= fNode.Parent <> nil
end;

function TJediXmlEngine.Get_ID: string;
begin
  Result:= 'JclSimpleXML';
end;

//function TJediXmlEngine.Get_NodeName: Boolean;
//begin
//  Result:= fNode.Name
//end;

function TJediXmlEngine.Get_ValidNode: Boolean;
begin
  Result:= fNode <> nil
end;

procedure TJediXmlEngine.Load(const aFilename: TFileName);
begin
  fXmlDoc.LoadFromFile(aFilename);
  SelectRootNode()
end;

procedure TJediXmlEngine.SelectChild(const aIndex: Integer);
begin
  fNode:= fNode.Items[aIndex]
end;

procedure TJediXmlEngine.SelectParent;
begin
  fNode:= fNode.Parent
end;

procedure TJediXmlEngine.SelectRootNode;
begin
  fNode:= fXmlDoc.Root
end;

end.
6
répondu g2mk 2012-02-29 06:30:14

essayer himXML par himitsu.

Il est libéré en vertu de l' MPL v1.1, GPL v3.0 ou LGPL v3.0 licence.

vous devrez Vous inscrire à l' Delphi-Praxis (Allemand) excellent site Delphi afin de pouvoir télécharger:

il a une performance très impressionnante et le la distribution inclut des démos démontrant cela. Je l'ai utilisé avec succès dans Delphi 2007, Delphi 2010 et Delphi XE.

3
répondu menjaraz 2012-02-29 05:08:24