2011-12-06 22 views
6

Estoy creando una instancia de TXMLDocument en tiempo de ejecución, para cargar y analizar un archivo XML. Puede verificar el código a continuación:Delphi - TXMLDocument creado en tiempo de ejecución genera AV, con el componente en el formulario está trabajando

unit Unit1; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, xmldom, XMLIntf, msxmldom, XMLDoc, StdCtrls; 

type 
    Txml = class(TForm) 
// XMLDocument1: TXMLDocument; 
    Memo1: TMemo; 
    procedure FormCreate(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

var 
    xml: Txml; 

implementation 

{$R *.dfm} 

procedure Txml.FormCreate(Sender: TObject); 
var i,j:integer; 
     aNode:IXMLNode; 
     ws:String; 
     XMLDocument1:TXMLDocument; 
begin 
Memo1.Lines.Clear; 
XMLDocument1 := TXMLDocument.Create(nil); 
try 
    XMLDocument1.LoadFromFile('C:\a.xml'); 
    XMLDocument1.Active := true; 
    aNode := XMLDocument1.ChildNodes.First; 
    while aNode<>nil do 
    begin 
    for i := 0 to aNode.ChildNodes.Count-1 do 
    begin 
    if aNode.ChildNodes[i].NodeName = 'Role' then 
     begin 
     Memo1.Lines.Add('Tag - '+aNode.ChildNodes[i].ChildNodes['Tag'].Text); 
     for j := 0 to aNode.ChildNodes[i].ChildNodes.Count-1 do 
     if aNode.ChildNodes[i].ChildNodes[j].HasChildNodes then 
     begin 
      ws := VarToStr(aNode.ChildNodes[i].ChildNodes[j].ChildValues['Tag']); 
      if trim(ws)<>'' then 
      Memo1.Lines.Add(ws); 
      ws := VarToStr(aNode.ChildNodes[i].ChildNodes[j].ChildValues['Value']); 
      if trim(ws)<>'' then 
      Memo1.Lines.Add(ws); 
     end; 
     end; 
    end; 
    aNode := aNode.NextSibling; 
    end; 
    XMLDocument1.Active := false; 
finally 
    FreeAndNil(XMLDocument1); 
end; 
end; 

end. 

El problema es que esto está generando un AV. Como probablemente haya visto, antes el componente estaba en el formulario (// XMLDocument1: TXMLDocument;).

¿Por qué cuando el componente estaba en el formulario el código estaba funcionando, pero cuando lo estoy creando en tiempo de ejecución genera AV?

LE: solución: basado en las respuestas/comentarios y ayuda de Delphi:

XMLDocument1 : IXMLDocument; //not TXMLDocument 

XMLDocument1 := LoadXMLDocument(...); 

FreeAndNil;// must be deleted 
+3

Use [IXMLDocument] (http://docwiki.embarcadero.com/VCL/en/XMLIntf.IXMLDocument) y como constructor [NewXMLDocument] (http://docwiki.embarcadero.com/VCL/en/ XMLDoc.NewXMLDocument). – TLama

+0

¿Dónde exactamente ocurre AV? – Kromster

+1

Debería hacer 'ANode: = nil;' después del ciclo para liberar la instancia del nodo antes de cerrar y liberar 'XMLDocument1'. –

Respuesta

14

Por lo que sé que usted debe utilizar la interfaz IDoc: IXMLDocument; lugar.

a partir de documentos:

Cuando se crea TXMLDocument sin dueño, se comporta como un objeto en interfaz . Es decir, cuando se lanzan todas las referencias a su interfaz , la instancia de TXMLDocument se libera automáticamente. Cuando TXMLDocument se crea con un propietario, sin embargo, se comporta como cualquier otro componente , y es liberado por su propietario.

En otras palabras, cuando se crea una instancia de TXMLDocument con un nil propietario, No llamada Free() o FreeAndNil() en la instancia, y que debe asignar el objeto a una variable IXMLDocument por lo que su referencia ahora-activa el recuento se gestiona correctamente.

+4

En otras palabras, al crear una instancia 'TXMLDocument' con un' nil' Propietario, * no * llame a 'Free()' o 'FreeAndNil()' en la instancia, y usted * debe * asignar el objeto a una variable 'IXMLDocument' por lo que su cuenta de referencia ahora activa se gestiona correctamente. –

2

Debe proporcionar un Owner a TXMLDocument al crearlo en tiempo de ejecución.

XMLDocument1 := TXMLDocument.Create(xml); 
+1

sí, de hecho, este problema es grave, pero todo este código se colocará en una clase especial, dentro de una unidad :) +1 – RBA

Cuestiones relacionadas