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

标签 xml delphi

我有一个大的 XML 文件要在代码中解析,如下例所示。问题似乎是分配给子节点 (IXMLNode) 的内存未释放,即使子节点超出范围也是如此。内存似乎只有在父 TXMLDocument 被停用 (Active:=false) 或被释放后才会被释放。所以我的代码,在加载 xml 文档后开始大约 380Mb,突然增加到 2Gb,这就是它结束的地方。将 childnode 设置为 nil 对内存使用没有影响。

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

var
  childnode: IXMLNode;

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

最佳答案

我知道你说过你不想要一个单独的 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;

Note: Any code is released into the public domain. No attribution required.

关于xml - EOutOfMemory 在 Delphi 中使用 TXMLDocument 解析大型 XML,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7168200/

相关文章:

java - 获取菜单组作为 View

java - 如何让 float 操作按钮在每次点击时旋转

用于 MIDI 输入/输出的 Delphi 库?

delphi - 为什么实现接口(interface)的类在泛型中使用时与接口(interface)类型不兼容?

delphi - TOorderedListEditDlg 有官方接口(interface)吗?

delphi - 添加 IFileDialogCustomize PushButton 事件

java - 如何配置 JAXB,使其默认修剪空格

XML 和 XSL 转换

xml - XSLT:检查是否有任何一组元素具有具有指定值的子元素

delphi - 如何在表单上绘制半透明图像?