2009-10-07 125 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