EOutOfMemory在Delphi中使用TXMLDocument解析大型XML

时间:2011-08-23 22:15:18

标签: xml delphi

我有一个大型XML文件要解析代码,如下面的示例所示。问题似乎是,即使childnode超出范围,分配给childnode(IXMLNode)的内存也不会被释放。一旦父TXMLDocument被取消激活(Active:= false)或释放,似乎只释放内存。所以我的代码,一旦加载了xml文档就开始大约380Mb,吹到2Gb,这就是它结束的地方。将childnode设置为nil对内存使用没有影响。

我的问题是如何显式释放分配给IXMLNode接口的内存。我不愿意使用不同的XML对象,我想我几乎已经尝试过控制节点接口的范围。

var
  childnode: IXMLNode;

for i:=0 to rootnode.ChildNodes.Count-1 do begin
    childnode:=rootnode.ChildNodes[i];
    ...
    childnode:=nil;
end;

1 个答案:

答案 0 :(得分:2)

我知道你说你不想要一个单独的XML库;但也许其他人想要示例代码:

var
   sax: SAXXMLReader60;
   stm: IStream;
begin
   //Get a stream around our large file
   stm := TStreamAdapter.Create(TFileStream.Create('USGovBudgetLineItems2008.xml', fmOpenRead   ));

   sax := CoSAXXMLReader60.Create;
   sax.contentHandler := TVBSAXContentHandler.Create;
   sax.parse(stm);
end;

我们使用SAXContentHandler对象来监听事件。

对于所有IDispatch个事件,您可以返回E_NOTIMPL(msxml甚至不会调用它们)。

所有其他的你可以插入你想要的任何代码:

TVBSAXContentHandler = class(TInterfacedObject, IVBSAXContentHandler)
protected
    { IDispatch }
    function GetTypeInfoCount(out Count: Integer): HResult; stdcall;
    function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult; stdcall;
    function GetIDsOfNames(const IID: TGUID; Names: Pointer; NameCount, LocaleID: Integer; DispIDs: Pointer): HResult; stdcall;
    function Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;
public
    { IVBSAXContentHandler }
    procedure Set_documentLocator(const Param1: IVBSAXLocator); safecall;
    procedure startDocument; safecall;
    procedure endDocument; safecall;
    procedure startPrefixMapping(var strPrefix: WideString; var strURI: WideString); safecall;
    procedure endPrefixMapping(var strPrefix: WideString); safecall;
    procedure startElement(var strNamespaceURI: WideString; var strLocalName: WideString;
                                var strQName: WideString; const oAttributes: IVBSAXAttributes); safecall;
    procedure endElement(var strNamespaceURI: WideString; var strLocalName: WideString;
                             var strQName: WideString); safecall;
    procedure characters(var strChars: WideString); safecall;
    procedure ignorableWhitespace(var strChars: WideString); safecall;
    procedure processingInstruction(var strTarget: WideString; var strData: WideString); safecall;
    procedure skippedEntity(var strName: WideString); safecall;
//      property documentLocator: IVBSAXLocator write Set_documentLocator;
end;
  

注意:任何代码都会发布到公共域中。无需归属。