使用TXMLDocument创建XML文档的问题

时间:2009-10-07 15:27:18

标签: delphi txmldocument

我是delphi的新手,现在我必须阅读创建一个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过程中的其余元素似乎没有做任何事情。在你的帮助下,我将非常高兴。

3 个答案:

答案 0 :(得分: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变量,只需使用结果 - 您不需要额外的StringList来查看XML:Result.Xml.Text
- 如果您创建一个,请不要忘记免费 sl StringList - 您返回的XmlDocument在函数外部无法使用,如果您尝试则会提供AV。

<强>为什么吗
这是因为XMLDocument旨在用作具有所有者的组件,或者用作接口,以便管理其生存期
使用接口来保存rootNode的事实导致它在CreateXmlDocument函数的末尾被销毁。如果你查看TXMLNode._Release中的代码,你会发现它会触发调用Destroy的TXMLDocument._Release,除非有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;

答案 1 :(得分:4)

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

  

注意:不要调用AddChild将子项添加到此文档的document元素中。将数据添加到XML文档时,请使用文档元素的AddChild方法或层次结构中应该是新节点的父节点的节点。

这就是你做得对吗? : - )

以下是关于Delphi XML Document Programming的介绍文章,并展示了如何使用TXMLDocument.DocumentElement属性而不是代码中对rootnode变量的定义。

答案 2 :(得分:2)

在我的类似实现中,我将res声明为IXMLDocument而不是TXMLDocument。

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