2009-10-07 91 views
8

我是delphi的新手,現在我必須閱讀創建xml。我的代碼如下:使用TXMLDocument構建XML文檔問題

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; 

問題是,子節點的數量增加,但res.XML爲空。更不用說generateDOM過程中的其他元素似乎沒有任何作用。我會很高興在你的幫助下。

+0

將是一件好事,如果你提供你正在使用的德爾福版本。在D2007的情況下查看我的答案。 – 2009-10-08 00:37:11

回答

12

聲明:經D2007測試。

你的代碼確實創建XML<label/>)如本修改功能:

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; 

但它要求一個很多言論的:
- 你不需要本地res變量,只需使用Result。
- 你並不需要一個額外的StringList看到XML:Result.Xml.Text
- 如果你創建了一個不要忘記免費的SL的StringList。
- 您返回的XmlDocument在函數外部不可用,並在您嘗試使用時提供AV。

爲什麼?
這是因爲一個XMLDocument旨在被用作組分與所有者,或作爲接口否則,爲了管理其壽命
您使用接口來保存rootNode的事實會導致它在CreateXmlDocument函數的末尾被銷燬。並且,如果您查看TXMLNode._Release中的代碼,則會看到觸發器TXMLDocument._Release會調用Destroy,除非XMLDocument有一個所有者(或擁有對其的引用的接口)。
這就是爲什麼XMLDocument在CreateXMLDocument函數內有效且填充的情況,但不在外部可用,除非您返回接口或提供所有者

替代解決方案如下

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

在我的類似實現中,我將res聲明爲IXMLDocument而不是TXMLDocument。

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

雖然這是在沒有所有者組件的情況下實例化TXmlDocument時所做的正確事情,但它與當前的問題無關。 – 2009-10-07 17:34:43

4

TXMLDocument.AddChild方法的Delphi Help說(底部):

注意:不要叫的AddChild一個孩子添加到這個文檔的文檔元素。將數據添加到XML文檔時,請使用文檔元素的AddChild方法或層次結構中應該是新節點的父節點的節點。

這就是你在做什麼的權利? :-)

這是一篇關於Delphi XML Document Programming的介紹性文章,展示瞭如何使用TXMLDocument.DocumentElement屬性,而不是在代碼中定義rootnode變量。

+0

您引用的介紹並未演示如何從頭開始創建新文檔。幫助頁面也沒有。問題中的代碼應該如何更改以使其正確? D2007中的 – 2009-10-07 17:39:26

+0

TXmlDocument.AddChild創建DocumentNode(如果尚未存在)並調用其AddChild。所以這不是問題。 – 2009-10-08 00:36:22

+0

埃爾溫,你在編輯你的答案,但我認爲你沒有解決我的評論。 – 2009-10-08 03:40:36