Delphi 修改现有 XML 文档结构
Delphi Modify Existing XML Document Structure
我有一个包含嵌套表格的现有 XML 文档。我想打开它,读入并修改结构(即添加或删除 columns/fields)。忽略嵌套表,这是完整的 XML 测试文档:
<DATAPACKET Version="2.0">
<METADATA>
<FIELDS>
<FIELD attrname="StringField" fieldtype="string" WIDTH="20" />
<FIELD attrname="IntField" fieldtype="i4" />
</FIELDS>
<PARAMS CHANGE_LOG="1 0 4 2 0 4" />
</METADATA>
<ROWDATA>
<ROW RowState="4" StringField="String" IntField="234" />
<ROW RowState="4" StringField="234" IntField="24" />
</ROWDATA>
</DATAPACKET>
以下代码在打开时抛出异常 "testField" 未找到,大概是因为它不存在于基础 XML 文件中。
ClientDataSet1.Close;
with TStringField.Create(ClientDataSet1) do
begin
FieldName := 'testField';
DataSet := ClientDataSet1;
end;
with ClientDataSet1 do
begin
CreateDataSet;
Open;
end;
如果我添加:
with ClientDataSet1 do
begin
FieldDefs.Clear;
Fields.Clear;
end;
没有抛出异常,但前两个字段消失并且新结构不会写入 XML 文档文件,除非我输入一些数据。
<DATAPACKET Version="2.0">
<METADATA>
<FIELDS>
<FIELD attrname="testField" fieldtype="string" WIDTH="20" />
</FIELDS>
<PARAMS CHANGE_LOG="1 0 4" />
</METADATA>
<ROWDATA>
<ROW RowState="4" testField="12321" />
</ROWDATA>
</DATAPACKET>
是否有标准或推荐的方法可以在不丢失数据的情况下向现有 XML 文档添加字段?
干杯,
坦纳
你的做法不太对;对于初学者,CreateDataSet
完全删除以前在 ClientDataSet
中的任何数据
接下来是您不希望使用持久字段来执行此操作 and/or
FieldDef 到位,因此在您进行更改时清除它们。之后是否创建它们取决于您,但如果您要在代码中创建 TFields,则应为 XML 元数据中的 every 字段创建一个,从CDS 中的空字段列表。
下面的示例项目应该向您展示如何获得您想要的东西。它
从 TMemo、Memo1 中的 XML 加载数据集。在我的,我只是复制
并从您的问题中粘贴 XML。这一步基本上是为了表明数据集
已正确填充;
然后,AddFieldToXML
中的代码将新字段添加到 XML 中的元数据中,并且
将结果复制到 Memo2,并将其保存到磁盘。注意:如所写,它不
将任何数据写入新字段,但您应该能够了解如何
从 AddFieldToXML
.
开始
最后,它通过从更改后的 XML
加载 CDS 来关闭并重新打开它
代码:
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, DBCtrls, Grids, DBGrids, DB, DBClient, MSXML;
type
TForm1 = class(TForm)
CDS1: TClientDataSet;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
DBNavigator1: TDBNavigator;
Button1: TButton;
Memo1: TMemo;
Memo2: TMemo;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
public
ExistingFN : String;
NewFN : String;
procedure AddFieldToXML;
procedure LoadNewData;
end;
[...]
procedure TForm1.FormCreate(Sender: TObject);
begin
ExistingFN := 'C:\Temp\Data.XML';
NewFN := 'C:\Temp\NewData.XML';
Memo1.Lines.SaveToFile(ExistingFN);
CDS1.Fields.Clear;
CDS1.FieldDefs.Clear;
CDS1.LoadFromFile(ExistingFN);
end;
procedure TForm1.AddFieldToXML;
var
XmlDoc: IXMLDOMDocument;
NodeList : IXmlDOMNodeList;
Node,
NewNode : IXmlDomNode;
E : IXmlDomElement;
PathQuery : String;
begin
PathQuery := '/DATAPACKET/METADATA/FIELDS';
Memo2.Lines.Clear;
XmlDoc := CoDOMDocument.Create; //CreateOleObject('Microsoft.XMLDOM') as IXMLDOMDocument;
XmlDoc.Async := False;
XmlDoc.LoadXML(Memo1.Lines.Text);
if xmlDoc.parseError.errorCode <> 0 then
raise Exception.Create('XML Load error:' + xmlDoc.parseError.reason);
NodeList := XmlDoc.documentElement.SelectNodes(PathQuery);
if NodeList.length > 0 then begin
E := XMLDoc.createElement('FIELD');
NewNode := E as IXMLDomNode;
E.setAttribute('attrname', 'testField');
E.setAttribute('fieldtype', 'string');
E.setAttribute('WIDTH', '20');
NodeList.item[0].appendChild(NewNode);
end;
Memo2.Lines.Text := XMLDoc.documentElement.xml;
Memo2.Lines.SaveToFile(NewFN);
end;
procedure TForm1.LoadNewData;
begin
CDS1.Close;
CDS1.Fields.Clear;
CDS1.FieldDefs.Clear;
CDS1.LoadFromFile(NewFN);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
AddFieldToXML;
LoadNewData;
end;
将新 XML 保存到磁盘后,您可以通过右键单击 CDS 并使用 Load from MyBase file
(对于 D7)将其加载到 IDE 中的 CDS ,类似的更高版本),然后根据需要创建持久性 TFields。
XML 代码适用于 D7 附带的 MSXML.Pas 版本,顺便说一句。我倾向于 post D7 的代码,除非 q 需要更高版本的 Delphi 版本。
我有一个包含嵌套表格的现有 XML 文档。我想打开它,读入并修改结构(即添加或删除 columns/fields)。忽略嵌套表,这是完整的 XML 测试文档:
<DATAPACKET Version="2.0">
<METADATA>
<FIELDS>
<FIELD attrname="StringField" fieldtype="string" WIDTH="20" />
<FIELD attrname="IntField" fieldtype="i4" />
</FIELDS>
<PARAMS CHANGE_LOG="1 0 4 2 0 4" />
</METADATA>
<ROWDATA>
<ROW RowState="4" StringField="String" IntField="234" />
<ROW RowState="4" StringField="234" IntField="24" />
</ROWDATA>
</DATAPACKET>
以下代码在打开时抛出异常 "testField" 未找到,大概是因为它不存在于基础 XML 文件中。
ClientDataSet1.Close;
with TStringField.Create(ClientDataSet1) do
begin
FieldName := 'testField';
DataSet := ClientDataSet1;
end;
with ClientDataSet1 do
begin
CreateDataSet;
Open;
end;
如果我添加:
with ClientDataSet1 do
begin
FieldDefs.Clear;
Fields.Clear;
end;
没有抛出异常,但前两个字段消失并且新结构不会写入 XML 文档文件,除非我输入一些数据。
<DATAPACKET Version="2.0">
<METADATA>
<FIELDS>
<FIELD attrname="testField" fieldtype="string" WIDTH="20" />
</FIELDS>
<PARAMS CHANGE_LOG="1 0 4" />
</METADATA>
<ROWDATA>
<ROW RowState="4" testField="12321" />
</ROWDATA>
</DATAPACKET>
是否有标准或推荐的方法可以在不丢失数据的情况下向现有 XML 文档添加字段?
干杯, 坦纳
你的做法不太对;对于初学者,CreateDataSet 完全删除以前在 ClientDataSet
中的任何数据接下来是您不希望使用持久字段来执行此操作 and/or FieldDef 到位,因此在您进行更改时清除它们。之后是否创建它们取决于您,但如果您要在代码中创建 TFields,则应为 XML 元数据中的 every 字段创建一个,从CDS 中的空字段列表。
下面的示例项目应该向您展示如何获得您想要的东西。它
从 TMemo、Memo1 中的 XML 加载数据集。在我的,我只是复制 并从您的问题中粘贴 XML。这一步基本上是为了表明数据集 已正确填充;
然后,
AddFieldToXML
中的代码将新字段添加到 XML 中的元数据中,并且 将结果复制到 Memo2,并将其保存到磁盘。注意:如所写,它不 将任何数据写入新字段,但您应该能够了解如何 从AddFieldToXML
. 开始
最后,它通过从更改后的 XML
加载 CDS 来关闭并重新打开它代码:
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls, DBCtrls, Grids, DBGrids, DB, DBClient, MSXML;
type
TForm1 = class(TForm)
CDS1: TClientDataSet;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
DBNavigator1: TDBNavigator;
Button1: TButton;
Memo1: TMemo;
Memo2: TMemo;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
public
ExistingFN : String;
NewFN : String;
procedure AddFieldToXML;
procedure LoadNewData;
end;
[...]
procedure TForm1.FormCreate(Sender: TObject);
begin
ExistingFN := 'C:\Temp\Data.XML';
NewFN := 'C:\Temp\NewData.XML';
Memo1.Lines.SaveToFile(ExistingFN);
CDS1.Fields.Clear;
CDS1.FieldDefs.Clear;
CDS1.LoadFromFile(ExistingFN);
end;
procedure TForm1.AddFieldToXML;
var
XmlDoc: IXMLDOMDocument;
NodeList : IXmlDOMNodeList;
Node,
NewNode : IXmlDomNode;
E : IXmlDomElement;
PathQuery : String;
begin
PathQuery := '/DATAPACKET/METADATA/FIELDS';
Memo2.Lines.Clear;
XmlDoc := CoDOMDocument.Create; //CreateOleObject('Microsoft.XMLDOM') as IXMLDOMDocument;
XmlDoc.Async := False;
XmlDoc.LoadXML(Memo1.Lines.Text);
if xmlDoc.parseError.errorCode <> 0 then
raise Exception.Create('XML Load error:' + xmlDoc.parseError.reason);
NodeList := XmlDoc.documentElement.SelectNodes(PathQuery);
if NodeList.length > 0 then begin
E := XMLDoc.createElement('FIELD');
NewNode := E as IXMLDomNode;
E.setAttribute('attrname', 'testField');
E.setAttribute('fieldtype', 'string');
E.setAttribute('WIDTH', '20');
NodeList.item[0].appendChild(NewNode);
end;
Memo2.Lines.Text := XMLDoc.documentElement.xml;
Memo2.Lines.SaveToFile(NewFN);
end;
procedure TForm1.LoadNewData;
begin
CDS1.Close;
CDS1.Fields.Clear;
CDS1.FieldDefs.Clear;
CDS1.LoadFromFile(NewFN);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
AddFieldToXML;
LoadNewData;
end;
将新 XML 保存到磁盘后,您可以通过右键单击 CDS 并使用 Load from MyBase file
(对于 D7)将其加载到 IDE 中的 CDS ,类似的更高版本),然后根据需要创建持久性 TFields。
XML 代码适用于 D7 附带的 MSXML.Pas 版本,顺便说一句。我倾向于 post D7 的代码,除非 q 需要更高版本的 Delphi 版本。