¿Cuál es el analizador XML más rápido disponible para Delphi?
Tenemos cadenas XML razonablemente grandes que actualmente analizamos usando MSXML2
Acabo de intentar usar MSXML6 esperando una mejora de velocidad y no tengo nada!
Actualmente creamos muchos documentos DOM y supongo que puede haber cierta sobrecarga en la interacción constante con la dll de MSXML2/6
¿Alguien conoce un componente XML mejor/más rápido para Delphi?
Si alguien puede sugerir una alternativa, y es más rápido, buscaríamos integrarla, pero eso sería mucho trabajo, así que esperemos que la estructura no sea demasiado diferente a la utilizada por MSXML
Estamos usando Delphi 2010
Paul
5 answers
Recientemente tuve un problema similar en el que el uso del analizador DOM de MSXML resultó ser demasiado lento para la tarea dada. Tuve que analizar documentos bastante grandes > 1MB y el consumo de memoria del analizador DOM era prohibitivo. Mi solución fue no usar un analizador DOM en absoluto, sino ir con el analizador SAX MSXML impulsado por eventos. Esto resultó ser mucho, mucho más rápido. Desafortunadamente el modelo de programación es totalmente diferente, pero dependiendo de la tarea, podría valer la pena. Craig Murphy ha publicado un excelente artículo sobre cómo usar el analizador SAX de MSXML en delphi: SAX, Delphi y Ex Em El
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-29 08:04:27
Hace algún tiempo tuve que serializar record
a formato XML; por ejemplo:
TTest = record
a : integer;
b : real;
end;
A
<Data> <a type="tkInteger">value</a> <b type="tkFloat">value</b> </Data>
Utilicé RTTI para navegar recursivamente a través de campos de registro y almacenar valores en XML. He probado algunos analizadores XML. No necesitaba el modelo DOM para crear xml, pero lo necesitaba para cargarlo de nuevo.
XML contiene alrededor de 310k nodos (10-15MBytes);
resultados presentados en la tabla a continuación, hay 6 columnas con tiempo en segundos;
1-tiempo para crear nodos y escribir valores
2-SaveToFile ();
3 = 1 + 2
4-LoadFromFile ();
5-navegar a través de nodos y leer valores
6 = 4 + 5
MSXML/Xerces/ADOM
- son diferentes proveedores para TXMLDocument
(DOMVendor
) JanXML
no funciona con unicode; Corregí algunos errores y guardé XML, pero la carga causa AV (o desbordamiento de pila, no recuerdo);manual
- significa escribir XML manualmente usando TStringStream
.
Usé Delphi2010, Win7x32, CPU Q8200/2.3 GHz, 4 Gb de RAM.
Actualización: Usted puede descargue el código fuente para esta prueba (registre la serialización a XML usando RTTI) aquí http://blog.karelia.pro/teran/files/2012/03/XMLTest.zip Todos los analizadores (Omni, Native, Jan) están incluidos (ahora el recuento de nodos en XML es de aproximadamente 270k), lo sentimos, no hay comentarios en el código.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-01 07:50:23
Sé que es una vieja pregunta, pero la gente podría encontrarla interesante:
Escribí una nueva biblioteca XML para Delphi (OXml): http://www.kluug.net/oxml.php
Cuenta con manejo directo de XML (lectura+escritura), analizador SAX, DOM y un analizador DOM secuencial. Uno de los beneficios es que OXml soporta Delphi 6-Delphi XE5, FPC/Lazarus y C++Builder en todas las plataformas (Win, MacOSX, Linux, iOS, Android).
OXml DOM se basa en registros / puntero y ofrece un mejor rendimiento que cualquier otra biblioteca XML:
La prueba de lectura devuelve el tiempo que el analizador necesita para leer un DOM XML personalizado de un archivo (columna "load") y para escribir valores de nodo en una función simulada constante (columna "navigate"). El archivo está codificado en UTF-8 y su tamaño es de aproximadamente 5,6 MB.
La prueba de escritura devuelve el tiempo que el analizador necesita para crear un DOM (columna "create") y escribir este DOM en un archivo (columna "save"). El archivo está codificado en UTF-8 y su tamaño es unos 11 MB.
+ El pobre rendimiento de escritura de OmniXML (original) fue el resultado del hecho de que OmniXML no usaba buffering para escribir. Así escribir a TFileStream era muy lento. Actualizé OmniXML y agregué soporte de almacenamiento en búfer. Puede obtener el último código OmniXML del SVN.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-11 20:58:04
Algún día he escrito un conjunto de pruebas XML muy simple. Sirve MSXML (D7 MSXML3?), Omni XML (bit old) y Jedi XML (latest stable).
Resultados de la prueba para el archivo de 1,52 MB:
Tiempo de carga del archivo XML MSXML: 240,20 [ms]
Selecciones de nodos XML MSXML: 1,09 [s]
Tiempo de carga del archivo XML OmniXML: 2,25 [s]
Selecciones de nodos XML OmniXML: 1,22 [s]
Tiempo de carga del archivo XML JclSimpleXML: 2,11 [s]
Y violación de acceso para selecciones de nodos JclSimpleXML: /
Desafortunadamente en realidad no tengo mucho tiempo para corregir por encima de AV, pero sorces están contenidos a continuación...
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.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-29 06:30:14
Darle una oportunidad a himXML por himitsu.
Está publicado bajo MPL v1.1 , la GPL v3.0 o LGPL v3.0 licencia.
Tendrá que registrarse en el Delphi-Praxis (alemán) excelente sitio Delphi para poder descargar:
Tiene un rendimiento muy impresionante y la distribución incluye demos que lo demuestran. Lo he usado con éxito en Delphi 2007, Delphi 2010 y Delphi XE.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-29 05:08:24