2009-10-07 10 views
8

Je suis nouveau sur Delphi et maintenant je dois lire créer un fichier XML. mon code est le suivant:Problème de création d'un document XML à l'aide de 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; 

Le problème est, le nombre de nœuds enfants augmente mais res.XML est vide. Sans oublier que le reste des éléments de la procédure generateDOM ne semble pas faire quoi que ce soit. Je serai très heureux avec votre aide.

+0

Ce serait bien si vous avez fourni la version Delphi que vous utilisez. Voir ma réponse dans le cas de D2007. –

Répondre

12

Clause de non-responsabilité: Testé avec D2007.

Votre code ne crée en effet le XML (<label/>) comme indiqué dans cette fonction modifiée:

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; 

Mais il demande beaucoup de remarques :
- Vous ne ont pas besoin variable locale res, il suffit d'utiliser le résultat.
- Vous n'avez pas besoin d'un StringList supplémentaire pour voir le XML: Result.Xml.Text
- N'oubliez pas de Gratuit le sl StringList si vous en créez un.
- Le document XmlDocument que vous renvoyez est inutilisable en dehors de la fonction et donne un AV si vous essayez.

Pourquoi?
C'est parce qu'un XMLDocument est destiné à être utilisé comme composant avec un propriétaire, ou comme interface autrement, afin de gérer sa vie .
Le fait que vous utilisiez une interface pour stocker rootNode entraîne sa destruction à la fin de la fonction CreateXmlDocument. Et si vous regardez le code dans TXMLNode._Release, vous verrez qu'il déclenche TXMLDocument._Release qui appelle Destroy sauf s'il y a un propriétaire pour XMLDocument (ou une interface contenant une référence).
C'est pourquoi le XMLDocument est valide et rempli à l'intérieur de la fonction CreateXMLDocument mais n'est pas disponible à l'extérieur, sauf si vous renvoyez une interface ou fournissez un propriétaire.

Voir les solutions de rechange ci-dessous:

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

Dans ma mise en œuvre similaire, je déclare res comme IXMLDocument au lieu de TXMLDocument.

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

Bien que ce soit la bonne chose à faire lors de l'instanciation d'un TXmlDocument sans un composant propriétaire, ce n'est pas pertinent pour le problème en question. –

4

La Delphi Help de la méthode TXMLDocument.AddChild dit (en bas):

Note: Ne pas appeler AddChild d'ajouter un enfant à l'élément de document de ce document. Lorsque vous ajoutez des données au document XML, utilisez la méthode AddChild de l'élément de document ou du nœud de la hiérarchie qui doit être le parent du nouveau nœud.

Et c'est ce que vous faites correctement? :-)

Voici un article d'introduction sur Delphi XML Document Programming et montre comment vous pouvez travailler avec la propriété TXMLDocument.DocumentElement au lieu de votre définition de la variable rootnode dans votre code.

+0

L'introduction que vous citez ne montre pas comment créer un nouveau document à partir de zéro. La page d'aide non plus. Comment le code de la question devrait-il changer pour faire les choses correctement? –

+0

dans D2007 TXmlDocument.AddChild crée le DocumentNode s'il n'est pas déjà là et appelle son AddChild. Donc ce n'est pas le problème. –

+0

Erwin, vous éditez votre réponse, mais je ne pense pas que vous avez adressé mon commentaire. –

Questions connexes