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
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
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
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.
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.
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.
+ 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.
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.
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.