在Delphi 10.1中生成XML文件并执行基本的XML操作?

时间:2016-09-28 07:33:10

标签: xml delphi delphi-10.1-berlin

我想使用以下格式在Delphi 10.1中创建XML文件

<EmployeeDB>
<Employees>
<Employee e.id="1">
  <eName>value from Edit Box edtName</eName>
<ePlace>value from Edit Box edtPlace</ePlace>
</Employee >
<Employee e.id="2">
  <eName>value from Edit Box edtName</eName>
<ePlace>value from Edit Box edtPlace</ePlace>
</Employee >
<Employee  e.id="3">
  <eName>value from Edit Box edtName</eName>
<ePlace>value from Edit Box edtPlace</ePlace>
</Employee >
</Employees>
</EmployeeDB>

我想从注册表单中获取数据,当单击“确定”按钮时,它应该将编辑框,RadioButtons等数据添加到XML文件中。

我是Delphi Programming的新手,帮我整理一下。

我尝试用这种方式编写代码:

unit XMLTrail;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, XMLIntf, XMLDoc, ComObj, xmldom,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  Tfrm_XMLTrail = class(TForm)
    edt_eID: TEdit;
    edtName: TEdit;
    edtPlace: TEdit;
    Memo1: TMemo;
    btnAdd: TButton;
    procedure btn_AddClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    procedure LoadXML;
    procedure SaveXML;
  public
    { Public declarations }
    XMLDoc1: TXmlDocument;

    iNode, Root1, Root2, Child_Attrib_Name, Child_Attrib_Place: IXmlNode;
    function GetEmployeeDBNode(XMLDoc: TXmlDocument): IXmlNode;
    function GetEmployeesNode(EmployeeDBNode: IXmlNode): IXmlNode;

  end;

var
  frm_XMLTrail: Tfrm_XMLTrail;

implementation

{$R *.dfm}

const
  scXmlTemplate = '<EmployeeDB>'#13#10 + '  <Employees>'#13#10 +
    '  </Employees>'#13#10 + '</EmployeeDB>';

  scXmlFileName =
    'C:\Users\Rajesh\Documents\Embarcadero\Studio\Projects\Samples\XML trail\Win32\Debug\nicexml.xml';

procedure Tfrm_XMLTrail.btn_AddClick(Sender: TObject);
begin
  XMLDoc1.Active := true;
  iNode := XMLDoc1.DocumentElement;
  Root1 := iNode.ChildNodes.FindNode('Employees');
  Root2 := Root1.AddChild('Employee');
  Root2.Attributes['e.id'] := edt_eID.Text;
  Child_Attrib_Name := Root2.AddChild('eName');
  Child_Attrib_Name.Text := edtName.Text;
  Child_Attrib_Place := Root2.AddChild('ePlace');
  Child_Attrib_Place.Text := edtPlace.Text;
  XMLDoc1.Active := true;
  XMLDoc1.SaveToFile(scXmlFileName);

end;

procedure Tfrm_XMLTrail.FormCreate(Sender: TObject);
begin
  XMLDoc1 := TXmlDocument.Create(nil);
  if not FileExists(scXmlFileName) then
  begin
    // XMLDoc1 := TXmlDocument.Create(nil);
    XMLDoc1.Active := true;
    XMLDoc1.Options := [doNodeAutoIndent];
    iNode := XMLDoc1.AddChild('UmangEmployeeDB');
    Root1 := iNode.AddChild('Employees');
  end
  else
  begin
    LoadXML;
  end;
end;

procedure Tfrm_XMLTrail.LoadXML;
begin
  XMLDoc1.LoadFromFile(scXmlFileName);
  Memo1.Lines.Text := XMLDoc1.XML.Text;
  // SaveXML;
  // Memo1.Lines.LoadFromFile(scXmlFileName);

  // XMLDoc1 := TXmlDocument.Create(nil);
  // Assert(Root1 <> Nil);
end;

procedure Tfrm_XMLTrail.SaveXML;
begin
  Memo1.Lines.SaveToFile(scXmlFileName);
end;

end.

但是它返回了如下的XML文件:

<EmployeeDB>
    <Employees>
        <Employee e.id="2">
            <eName>sssss</eName>
            <ePlace>fgr</ePlace>
        </Employee>
        <Employee e.id="2">
            <eName>sssss</eName>
            <ePlace>fgr</ePlace>
        </Employee>
    </Employees>
</EmployeeDB>

应用程序的UI就像这个Image

输入数据后单击“确定”按钮时,每次单击“确定”按钮时,都应通过创建新的<Employee/>节点将数据写入XML文件。

2 个答案:

答案 0 :(得分:2)

我通常不喜欢提交第二个答案但你似乎没有遵循 我在第一篇文章中所说的话。

下面是一个示例项目,它生成一个新的Xml文件并添加一个新的Employee 每次单击btnAdd按钮时节点。希望代码中的注释足以让您前进。

请注意,此项目使用MSXML.Pas单元中定义的Xml接口, 使用XmlDoc单元。

unit XmlGenerateu;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, MSXML;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    edtName: TEdit;
    edtPlace: TEdit;
    btnAdd: TButton;
    procedure btnAddClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    procedure LoadXML;
    procedure SaveXML;
    procedure GenerateXML;
    function CreateEmployeeNode: IXmlDomElement;
  protected
  public
    XMLDoc : IXmlDomDocument;
    EmployeesNode : IXmlDomNode;
    NewEmployeeNode : IXmlDomNode;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

const
  scXmlTemplate =
    '<EmployeeDB>'#13#10
     + '  <Employees>'#13#10
     + '  </Employees>'#13#10
     + '</EmployeeDB>';

  scXmlFileName = 'C:\Temp\Employees.Xml';

procedure TForm1.btnAddClick(Sender: TObject);
begin
  NewEmployeeNode := CreateEmployeeNode;
  Memo1.Lines.Text := XmlDoc.xml;
  SaveXML;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  LoadXML;
end;

procedure TForm1.LoadXML;
begin
  //  If there is no existing Xml file create it from our Xml template
  //  and save it to disk
  if not FileExists(scXmlFileName) then begin
    Memo1.Lines.Text := scXmlTemplate;
    SaveXML;
  end;
  Memo1.Lines.LoadFromFile(scXmlFileName);

  //  Create the XmlDoc object
  XmlDoc := CoDomDocument.Create;
  //  Load it from Memo1
  Assert(XmlDoc.LoadXml(Memo1.Lines.Text));

  //  Find the Employees node
  EmployeesNode := XmlDoc.selectSingleNode('/EmployeeDB/Employees');
  //  Complain if we didn't find it
  Assert(EmployeesNode <> Nil);

end;

procedure TForm1.SaveXML;
begin
  Memo1.Lines.SaveToFile(scXmlFileName);
end;

function TForm1.CreateEmployeeNode : IXmlDomElement;
var
  EmployeeID : Integer;
  NameElement,
  PlaceElement : IXmlDomElement;
begin
  //  First, generate the ID for the new Employee
  EmployeeID :=  EmployeesNode.childNodes.length + 1;

  //  Next, get the XmlDoc to create a new Element
  Result := XmlDoc.createElement('Employee');

  //  Set the new Element's ID attribute
  Result.setAttribute('e.id', IntToStr(EmployeeID));

  //  Put the new Employee node at the end of the list of Employee nodes
  EmployeesNode.appendChild(Result);

  //  Finally, createt eName and ePlace children of the new Employee
  NameElement := XmlDoc.createElement('eName');
  NameElement.text := edtName.Text;
  Result.appendChild(NameElement);

  PlaceElement := XmlDoc.createElement('ePlace');
  PlaceElement.text := edtPlace.Text;
  Result.appendChild(PlaceElement);
end;

<强>更新

您在评论中询问是否可以使用TXmlDocument代替 MSXML.Pas单元中的接口。我认为这将是一个很好的自我指导 练习所以我不打算用完整的代码来做,但这里有一些提示。

需要进行一些细节更改,例如如何从中加载XMLDocument Memo1,但主要的变化是如何找到Employees节点 的XML文档。最简单的方法是使用XPath查询(请参阅 上面的代码中的SelectSingleNode)但涉及使用相同的XML接口 就像在MSXML.Pas中一样,如果你想这样做,你也可以避免使用 TXMLDocument的。如果你想避免使用XPath,那么你可以编写两个函数, 返回EmployeeDB和Employees节点。这些可能看起来像这样

function TForm1.GetEmployeeDBNode(XmlDoc : TXmlDocument) : IXmlNode;
begin
  Result := XmlDoc.DocumentElement;
  Assert(Result <> Nil);
  Assert(Result.NodeName = 'EmployeeDB');
end;

function TForm1.GetEmployeesNode(EmployeeDBNode : IXmlNode) : IXmlNode;
begin
  Result := EmployeeDBNode.ChildNodes.First;
  Assert(Result <> Nil);
  Assert(Result.NodeName = 'Employees');
end;

您可以在CreateEmployeeNode的改编版本中使用这些功能 通过在节点上调用AddChild('Employee')来添加新的Employee节点 由GetEmployeesNode返回。

顺便说一下,编写这些假定XML文档具有固定结构的函数的需要说明了为什么使用XPath更为可取,因为它更容易适应不同的XML结构,例如,如果EmployeeDB嵌入在一些更大的Xml结构中。使用XPath,这只需要更改XPath查询字符串。

答案 1 :(得分:1)

必须以这种方式修改代码,使用TXMLDocument创建XML文档,并在运行时将子元素附加到同一文档。谢谢你@MartynA先生的帮助..

unit XMLTrail;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics, XMLIntf, XMLDoc, ComObj, xmldom,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  Tfrm_XMLTrail = class(TForm)
    edt_eID: TEdit;
    edtName: TEdit;
    edtPlace: TEdit;
    Memo1: TMemo;
    btnAdd: TButton;
    procedure btn_AddClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    procedure LoadXML;
    procedure SaveXML;
  public
    { Public declarations }
    gXMLDoc1: TXmlDocument;
    giNode, gRoot1, gRoot2, gChild_Attrib_Name, gChild_Attrib_Place: IXmlNode;
    function GetEmployeeDBNode(XMLDoc: TXmlDocument): IXmlNode;
    function GetEmployeesNode(EmployeeDBNode: IXmlNode): IXmlNode;
    function GetEmployeeNodes(EmployeeNodes: IXmlNode): IXmlNode;
  end;

var
  frm_XMLTrail: Tfrm_XMLTrail;

implementation

{$R *.dfm}

const
  scXmlTemplate = '<EmployeeDB>'#13#10 + '  <Employees>'#13#10 +
    '  </Employees>'#13#10 + '</EmployeeDB>';

  scXmlFileName =
    '..\nicexml.xml';

procedure Tfrm_XMLTrail.btn_AddClick(Sender: TObject);
begin
  gXMLDoc1.Active := true;
  giNode := gXMLDoc1.DocumentElement;
  gRoot1 := giNode.ChildNodes.FindNode('Employees');
  gRoot2 := gRoot1.AddChild('Employee');
  gRoot2.Attributes['e.id'] := edt_eID.Text;
  gChild_Attrib_Name := gRoot2.AddChild('eName');
  gChild_Attrib_Name.Text := edtName.Text;
  gChild_Attrib_Place := gRoot2.AddChild('ePlace');
  gChild_Attrib_Place.Text := edtPlace.Text;
  gXMLDoc1.Active := true;
  gXMLDoc1.XML.Text := XMLDoc.FormatXMLData(gXMLDoc1.XML.Text);
  Memo1.Lines.Text := gXMLDoc1.XML.Text;
  SaveXML;
end;

procedure Tfrm_XMLTrail.FormCreate(Sender: TObject);
begin
  gXMLDoc1 := TXmlDocument.Create(self);
  if not FileExists(scXmlFileName) then
  begin
    // XMLDoc1 := TXmlDocument.Create(nil);
    gXMLDoc1.Active := true;
    gXMLDoc1.Options := [doNodeAutoIndent];
    giNode := gXMLDoc1.AddChild('EmployeeDB');
    gRoot1 := giNode.AddChild('Employees');
  end
  else
  begin
    LoadXML;
  end;
end;

procedure Tfrm_XMLTrail.LoadXML;
begin
  gXMLDoc1.LoadFromFile(scXmlFileName);
  gXMLDoc1.Active := true;
  Memo1.Lines.Text := gXMLDoc1.XML.Text;
end;

procedure Tfrm_XMLTrail.SaveXML;
begin
  Memo1.Lines.SaveToFile(scXmlFileName);
end;

function Tfrm_XMLTrail.GetEmployeeDBNode(XMLDoc: TXmlDocument): IXmlNode;
begin
  Result := XMLDoc.DocumentElement;
  Assert(Result <> Nil);
  Assert(Result.NodeName = 'EmployeeDB');
end;

function Tfrm_XMLTrail.GetEmployeesNode(EmployeeDBNode: IXmlNode): IXmlNode;
begin
  Result := EmployeeDBNode.ChildNodes.First;
  Assert(Result <> Nil);
  Assert(Result.NodeName = 'Employees');
end;

function Tfrm_XMLTrail.GetEmployeeNodes(EmployeeNodes: IXmlNode): IXmlNode;
begin
  Result := EmployeeNodes.ChildNodes.First;
  Assert(Result <> Nil);
  Assert(Result.NodeName = 'Employee');
end;

end.