2009-10-07 6 views
8

Sono nuovo di Delphi e ora devo leggere creare un XML. il mio codice è il seguente:Problema di creazione di un documento XML utilizzando 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; 

Il problema è che il conteggio dei nodi figlio aumenta ma res.XML è vuoto. Senza contare che il resto degli elementi nella procedura generateDOM non sembra fare nulla. Sarò molto contento del tuo aiuto.

+0

sarebbe bene se hai fornito la versione di Delphi che si sta utilizzando. Vedi la mia risposta in caso di D2007. –

risposta

12

Disclaimer: Testato con D2007.

il codice fa infatti creare il XML (<label/>) come mostrato in questa funzione modificata:

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; 

Ma richiede un sacco di osservazioni:
- Non hanno bisogno di un variabile res locale, basta usare il risultato.
- Non è necessario un elenco di stringhe aggiuntivo per visualizzare il codice XML: Result.Xml.Text
- Non dimenticare di gratuito sl StringList se ne crei uno.
- Il documento Xml che si restituisce non è utilizzabile fuori dalla funzione e fornisce un AV se si prova.

Perché?
E 'a causa di un XMLDocument è destinato ad essere usato come componente con un proprietario, o come un interfaccia in caso contrario, al fine di gestire la propria vita .
Il fatto che si utilizzi un'interfaccia per contenere rootNode ne provoca la distruzione al termine della funzione CreateXmlDocument. E se guardate il codice in TXMLNode._Release, vedrete che si innesca TXMLDocument._Release che chiama Destroy a meno che non ci sia un proprietario per XMLDocument (o un'interfaccia che contiene un riferimento ad esso).
Questo è il motivo per cui XMLDocument è valido e compilato all'interno della funzione CreateXMLDocument ma non è disponibile al di fuori di esso a meno che non si restituisca un'interfaccia o si fornisca un proprietario.

visualizzare le soluzioni alternative sotto:

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

Nella mia implementazione simile, dichiaro res come IXMLDocument invece di TXMLDocument.

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

Anche se questa è la cosa corretta da fare quando si istanzia un TXmlDocument senza un componente proprietario, è irrilevante per il problema in questione. –

4

Il Delphi Help del metodo di TXMLDocument.AddChild dice (in basso):

Nota: Non chiamare AddChild per aggiungere un bambino per l'elemento del documento di questo documento. Quando si aggiungono dati al documento XML, utilizzare il metodo AddChild dell'elemento del documento o del nodo nella gerarchia che dovrebbe essere il genitore del nuovo nodo.

E questo è quello che stai facendo giusto? :-)

Questo è un articolo introduttivo su Delphi XML Document Programming e mostra come è possibile utilizzare la proprietà TXMLDocument.DocumentElement anziché la definizione della variabile rootnode nel codice.

+0

L'introduzione citata non dimostra come creare un nuovo documento da zero. Neanche la pagina di aiuto. Come dovrebbe cambiare il codice nella domanda per renderlo corretto? –

+0

in D2007 TXmlDocument.AddChild crea il DocumentNode se non è già presente e chiama AddChild. Quindi non è il problema. –

+0

Erwin, stai modificando la tua risposta, ma non penso che tu abbia risposto al mio commento. –