我有一个带嵌套表的现有XML文档。我想打开它,读入并修改结构(即添加或删除列/字段)。忽略嵌套表,这里是一个完整的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>
以下代码在打开时引发异常&#34; testField&#34;没找到,大概是因为它不存在于基础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 doc文件。
<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文档添加字段?
干杯, 唐纳
答案 0 :(得分:1)
你并没有以正确的方式解决这个问题;对于初学者,CreateDataSet 完全删除以前在ClientDataSet中的任何数据
接下来就是你不想用持久字段和/或来做这件事 FieldDef就位,在您进行更改时清除它们。您之后是否创建它们取决于您,但如果您要在代码中创建TFields,则应从XML元数据中的每个字段创建一个,从CDS中的空字段列表开始。
下面的示例项目应该向您展示如何获得您想要的东西。它
从TMemo,Memo1中的XML加载数据集。在我的,我只是复制 并从您的q粘贴XML。这一步基本上是为了显示数据集 已正确填充;
然后,AddFieldToXML
中的代码将新字段添加到XML中的元数据中
将结果复制到Memo2,并将其保存到磁盘。注意:如上所述,它没有
将任何数据写入新字段,但您应该能够了解如何
从AddFieldToXML
。
最后,它通过从更改的XML
加载CDS来关闭并重新打开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中,然后创建如果你愿意,可以使用持久性TField。
XML代码适用于D7,btw附带的MSXML.Pas版本。我倾向于为D7发布代码,除非q要求后来的Delphi版本。