【问题标题】:Issue building an XML document using TXMLDocument使用 TXMLDocument 构建 XML 文档的问题
【发布时间】:2010-12-04 16:16:48
【问题描述】:

我是 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 过程中的其余元素似乎没有做任何事情。有你的帮助我会很高兴的。

【问题讨论】:

  • 如果您提供您正在使用的 Delphi 版本会很好。如果是 D2007,请参阅我的答案。

标签: delphi txmldocument


【解决方案1】:

免责声明:使用 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】:

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

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

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

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

    【讨论】:

    • 您引用的介绍并未演示如何从头开始创建新文档。帮助页面也没有。应该如何更改问题中的代码以使其正确?
    • 在 D2007 TXmlDocument.AddChild 中创建 DocumentNode(如果还没有的话)并调用它的 AddChild。所以这不是问题。
    • 欧文,你正在编辑你的答案,但我认为你没有解决我的评论。
    • 这不是我想要的,但帮助链接非常有用,因为我只能访问德文版的 delphi 帮助,而我正在在线查看英文版。跨度>
    【解决方案3】:

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

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

    【讨论】:

    • 虽然在实例化没有所有者组件的 TXmlDocument 时这样做是正确的,但它与手头的问题无关。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-06
    • 1970-01-01
    相关资源
    最近更新 更多