我们目前使用MSXML2
解析了相当大的XML字符串我刚刚尝试使用MSXML6希望提高速度而且什么都没有!
我们目前创建了很多DOM文档,我想在与MSXML2 / 6 dll不断交互时可能会有一些开销
有没有人知道Delphi的更好/更快的XML组件?
如果有人可以提出替代方案,并且速度更快,我们会考虑整合它,但这将是很多工作,所以希望结构不会与MSXML使用的结构太不相同
我们正在使用Delphi 2010
保
答案 0 :(得分:35)
前段时间我不得不将record
序列化为XML格式;例如:
TTest = record
a : integer;
b : real;
end;
要
<Data> <a type="tkInteger">value</a> <b type="tkFloat">value</b> </Data>
我使用RTTI递归浏览记录字段并将值存储到XML。 我尝试过很少的XML Parsers。我不需要DOM模型来创建xml,但是需要它来加载它。
XML包含 310k 节点(10-15MBytes);
结果如下表所示,有6列,时间以秒为单位;
1 - 创建节点和写入值的时间
2 - SaveToFile();
3 = 1 + 2
4 - LoadFromFile();
5 - 浏览节点并读取值
6 = 4 + 5
MSXML/Xerces/ADOM
- 是TXMLDocument
(DOMVendor
)的差异供应商
JanXML
不适用于unicode;我修复了一些错误,并保存了XML,但加载导致AV(或堆栈溢出,我不记得了);
manual
- 表示使用TStringStream
手动编写XML。
我使用的是Delphi2010,Win7x32,Q8200 CPU / 2.3GHz,4Gb内存。
更新:您可以下载此测试的源代码(使用RTTI将序列化记录到XML)http://blog.karelia.pro/teran/files/2012/03/XMLTest.zip包含所有解析器(Omni,Native,Jan)(现在XML中的节点数约为270k),抱歉代码中没有注释。
答案 1 :(得分:22)
我知道这是一个老问题,但人们可能会觉得有趣:
我为Delphi(OXml)编写了一个新的XML库:http://www.kluug.net/oxml.php
它具有直接XML处理(读取+写入),SAX解析器,DOM和顺序DOM解析器。 其中一个好处是OXml在所有平台(Win,MacOSX,Linux,iOS,Android)上都支持Delphi 6-Delphi XE5,FPC / Lazarus和C ++ Builder。
OXml DOM是基于记录/指针的,并且提供比任何其他XML库更好的性能:
读取测试返回解析器需要从文件读取自定义XML DOM的时间(列“load”)并将节点值写入常量虚函数(列“导航”) 。 该文件以UTF-8编码,其大小约为5.6 MB。
写入测试返回解析器创建DOM(“create”列)并将此DOM写入文件(“save”列)所需的时间。 该文件采用UTF-8编码,大小约为11 MB。
+糟糕的OmniXML(原创)写作性能是OmniXML没有使用缓冲进行写入的结果。因此,写入TFileStream非常慢。我更新了OmniXML并添加了缓冲支持。您可以从SVN获取最新的OmniXML代码。
答案 2 :(得分:11)
最近我遇到了类似的问题,使用MSXML DOM解析器证明对于给定的任务来说太慢了。我不得不解析相当大的文档&gt; 1MB和DOM解析器的内存消耗是令人望而却步的。 我的解决方案是根本不使用DOM解析器,而是使用事件驱动的MSXML SAX解析器。事实证明,这要快得多。不幸的是,编程模型完全不同,但依赖于任务,它可能是值得的。 Craig Murphy发表了一篇关于如何在delphi中使用MSXML SAX解析器的优秀文章: SAX, Delphi and Ex Em El
答案 3 :(得分:6)
总有一天我写了非常简单的XML测试套件。它提供MSXML(D7 MSXML3?),Omni XML(旧位)和Jedi XML(最新稳定版)。
1,52 MB文件的测试结果:
XML文件加载时间MSXML:240,20 [ms]
XML节点选择MSXML:1,09 [s]
XML文件加载时间OmniXML:2,25 [s]
XML节点选择OmniXML:1,22 [s]
XML文件加载时间JclSimpleXML:2,11 [s]
和JclSimpleXML节点选择的访问冲突:|
不幸的是我实际上没有太多时间纠正上面的AV,但是下面包含了... ...
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.
答案 4 :(得分:3)
在 MPL v1.1 , GPL v3.0 或 LGPL v3.0 许可下发布。
您必须注册Delphi-Praxis(德国)优秀的Delphi网站才能下载:
它有一个非常令人印象深刻的表现,分发包括演示证明。我已经成功地在Delphi 2007,Delphi 2010和Delphi XE中使用它。