2009-10-07 12 views
8

Soy nuevo en Delphi y ahora tengo que leer crear un xml. mi código es el siguiente:Problema al generar un documento XML usando TXMLDocument

function foo.createXMLDocument(): TXMLDocument; 
var 
    res: TXMLDocument; 
    rootNode: IXMLNode; 
    sl : TStringList; 
begin 
    res := TXMLDocument.Create(nil); 
    res.Active := true; 
    rootNode := res.AddChild('label'); 
    // create string for debug purposes 
    sl := TStringList.Create; 
    sl.Assign(res.XML);// sl is empty after this assignment 
    //add more elements 
    generateDOM(rootNode); 

    Result := res; 
end; 

El problema es que el recuento de nodos secundarios aumenta pero res.XML está vacío. Sin mencionar que el resto de los elementos en el procedimiento generateDOM no parecen estar haciendo nada. Estaré muy contento con tu ayuda.

+0

sería bueno si proporcionó la versión de Delphi que está utilizando. Ver mi respuesta en caso de D2007. –

Respuesta

12

responsabilidad: Probado con D2007.

Su código no crear de hecho el XML (<label/>) como se muestra en esta función modificada:

function createXMLDocument(): TXMLDocument; 
var 
    res: TXMLDocument; 
    rootNode: IXMLNode; 
    sl : TStringList; 
begin 
    res := TXMLDocument.Create(nil); 
    res.Active := true; 
    rootNode := res.AddChild('label'); 
    // create string for debug purposes 
    sl := TStringList.Create; // not needed 
    sl.Assign(res.XML); // Not true: sl is empty after this assignment 
    ShowMessage(sl.text);// sl is NOT empty! 
    sl.Free;    // don't forget to free it! use try..finally.. to guarantee it! 
    //add more elements 
// generateDOM(rootNode); 
    Result := res; 
end; 

pero requiere una gran cantidad de observaciones :
- Usted no necesita una variable de res local, solo use el resultado.
- No necesita StringList adicional para ver el XML: Result.Xml.Text
- No se olvide de gratuito sl StringList si crea uno.
- El XmlDocument que regrese no se puede utilizar fuera de la función y da un AV si intenta.

¿Por qué?
Es porque un XMLDocument está destinado a ser usado como un componente con un propietario, o como una Interface de otro modo, con el fin de gestionar su vida.
El hecho de que utilice una interfaz para contener rootNode hace que se destruya al final de la función CreateXmlDocument. Y si mira el código en TXMLNode._Release, verá que desencadena TXMLDocument._Release que llama Destrucción a menos que haya un Propietario para el XMLDocument (o una interfaz que contenga una referencia).
Esta es la razón por la XMLDocument es válida y poblada dentro de la función CreateXMLDocument pero no está disponible fuera de ella a menos que devuelva una interfaz o proporcionar un Propietario.

Ver las soluciones alternas a continuación:

function createXMLDocumentWithOwner(AOwner: TComponent): TXMLDocument; 
var 
    rootNode: IXMLNode; 
begin 
    Assert(AOwner <> nil, 'createXMLDocumentWithOwner cannot accept a nil Owner'); 
    Result := TXMLDocument.Create(AOwner); 
    Result.Active := True; 
    rootNode := Result.AddChild('label'); 
    OutputDebugString(PChar(Result.Xml.Text)); 
    //add more elements 
// generateDOM(rootNode); 
end; 

function createXMLDocumentInterface(): IXMLDocument; 
var 
    rootNode: IXMLNode; 
begin 
    Result := TXMLDocument.Create(nil); 
    Result.Active := True; 
    rootNode := Result.AddChild('label'); 
    OutputDebugString(PChar(Result.Xml.Text)); 
    //add more elements 
// generateDOM(rootNode); 
end; 


procedure TForm7.Button1Click(Sender: TObject); 
var 
    doc: TXmlDocument; 
    doc2: IXMLDocument; 
begin 
    ReportMemoryLeaksOnShutdown := True; 

    doc := createXMLDocument; 
    // ShowMessage(doc.XML.Text); // cannot use it => AV !!!! 
    // already freed, cannot call doc.Free; 

    doc := createXMLDocumentWithOwner(self); 
    ShowMessage(doc.XML.Text); 

    doc2 := createXMLDocumentInterface; 
    ShowMessage(doc2.XML.Text); 
end; 
2

En mi aplicación similares, declaro res como IXMLDocument en lugar de TXMLDocument.

var 
    XMLDoc: IXMLDocument; 
. 
. 
    XMLDoc := TXMLDocument.Create(nil); 
    XMLDoc.Active := True; 
. 
. 
    XMLDoc.SaveToFile(Filename); 
    XMLDoc.Active := False; 
+0

Aunque es lo correcto al crear un TXmlDocument sin un componente propietario, es irrelevante para el problema en cuestión. –

4

El método de Delphi Help TXMLDocument.AddChild dice (en la parte inferior):

Nota: No llame AddChild añadir un niño al elemento de documento de este documento. Al agregar datos al documento XML, use el método AddChild del elemento del documento o del nodo en la jerarquía que debería ser el padre del nuevo nodo.

Y esto es lo que estás haciendo ¿verdad? :-)

Aquí hay un artículo de introducción sobre Delphi XML Document Programming y muestra cómo puede trabajar con la propiedad TXMLDocument.DocumentElement en lugar de su definición de la variable rootnode en su código.

+0

La introducción que cita no demuestra cómo crear un documento nuevo desde cero. Tampoco lo hace la página de ayuda. ¿Cómo debería cambiar el código en la pregunta para que sea correcto? –

+0

en D2007 TXmlDocument.AddChild crea el DocumentNode si aún no está allí y llama a AddChild. Entonces no es el problema. –

+0

Erwin, usted está editando su respuesta, pero no creo que se haya dirigido a mi comentario. –

Cuestiones relacionadas