1

次の形式を使用して、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>

登録フォームからデータを取得したかったのですが、[OK] ボタンをクリックすると、編集ボックス、ラジオボタンなどのデータが XML ファイルに追加されます。

私は Delphi プログラミングが初めてなので、これを整理するのを手伝ってください。

私はこの方法でコードを書いてみました:

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はこの画像のようなものです。

<Employee/>データを入力した後にOKボタンをクリックすると、OKボタンをクリックするたびに新しいノードを作成してXMLファイルにデータを書き込む必要があります。

4

2 に答える 2

2

私は通常、2 番目の回答を送信するのは好きではありませんが、最初の回答で私が言ったことに従わなかったようです。

以下は、新しい Xml ファイルを生成し、btnAdd ボタンをクリックするたびに新しい Employee ノードを追加するサンプル プロジェクトです。コード内のコメントで十分に理解できるはずです。

このプロジェクトは、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;

アップデート

MSXML.Pas ユニットのインターフェイスの代わりに TXmlDocument を使用してこれを行うことができるかどうかをコメントで尋ねました。これは自己学習の良い練習になると思うので、それを行うための完全なコードを含めるつもりはありませんが、ここにいくつかのヒントがあります。

Memo1 から XMLDocument をロードする方法など、いくつかの詳細な変更が必要ですが、主な変更点は、XML ドキュメントの Employees ノードを見つける方法です。これを行う最も簡単な方法は、XPath クエリを使用することです (上記のコードの SelectSingleNode を参照)。ただし、これには、MSXML.Pas と同じ XML インターフェイスを使用する必要があり、それを行う場合は、TXmlDocument の使用を避けることもできます。XPath の使用を避けたい場合は、EmployeeDB ノードと Employees ノードを返す 2 つの関数を記述できます。これらはこのように見えるかもしれません

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 GetEmployeesNode によって返されたノードで AddChild('Employee') を呼び出すことにより、これらの関数を の適合バージョンで使用して、新しい Employee ノードを追加できます。

ところで、XML ドキュメントの構造が固定されていることを前提とするこれらの関数を作成する必要があることは、たとえば EmployeeDB がより大きな Xml 構造に埋め込まれている場合など、さまざまな XML 構造に対応する方が簡単であるため、XPath を使用することが望ましい理由を示しています。XPath を使用すると、XPath クエリ文字列を変更するだけで済みます。

于 2016-09-28T13:12:56.593 に答える
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.
于 2016-09-30T10:00:30.680 に答える