Delphi修改现有XML文档结构
我有一个包含嵌套表的现有XML文档。我想打开它,读入并修改结构(即添加或删除列/字段)。忽略嵌套表,下面是完整的XML测试文档:Delphi修改现有XML文档结构,xml,delphi,xml-parsing,tclientdataset,Xml,Delphi,Xml Parsing,Tclientdataset,我有一个包含嵌套表的现有XML文档。我想打开它,读入并修改结构(即添加或删除列/字段)。忽略嵌套表,下面是完整的XML测试文档: <DATAPACKET Version="2.0"> <METADATA> <FIELDS> <FIELD attrname="StringField" fieldtype="string" WIDTH="20" /> <FIELD attrname="IntField" fi
<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>
如果我加上:
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文档中
干杯,
坦纳你的做法不太正确;首先,创建数据集 完全删除以前在ClientDataSet中的所有数据 下一件事是,您不希望使用持久性字段和/或 FieldDef已就位,因此在进行更改时将其清除。以后是否创建这些字段取决于您自己,但如果要在代码中创建TFields,则应该从CD中的空字段列表开始,为XML元数据中的每个字段创建一个 下面的示例项目应该向您展示如何获得您想要的东西。它
- 从TMemo、Memo1中的XML加载数据集。在我的,我只是复制 并从您的q中粘贴XML。这一步基本上是为了显示数据集 已正确填充
- 然后,
中的代码将新字段添加到XML和XML中的元数据中 将结果复制到Memo2,并将其保存到磁盘。注:如前所述,不适用于 在新字段中写入任何数据,但您应该能够了解如何写入 从AddFieldToXML
执行此操作AddFieldToXML
使用
窗口、消息、系统工具、类、图形、控件、窗体、对话框、,
StdCtrls、ExtCtrls、DBCtrls、Grids、DBGrids、DB、DBClient、MSXML;
类型
TForm1=类(TForm)
CDS1:TClientDataSet;
数据源1:TDataSource;
DBGrid1:TDBGrid;
DBNavigator1:TDBNavigator;
按钮1:t按钮;
备忘录1:TMemo;
备忘录2:TMemo;
程序按钮1点击(发送方:ToObject);
过程表单创建(发送方:ToObject);
公众的
现有fn:字符串;
NewFN:字符串;
程序AddFieldToXML;
程序加载新数据;
结束;
[...]
过程TForm1.FormCreate(发送方:TObject);
开始
现有fn:=“C:\Temp\Data.XML”;
NewFN:=“C:\Temp\NewData.XML”;
Memo1.Lines.SaveToFile(现有fn);
CDS1.Fields.Clear;
CDS1.FieldDefs.Clear;
CDS1.LoadFromFile(现有fn);
结束;
程序TForm1.AddFieldToXML;
变量
XmlDoc:IXMLDOMDocument;
节点列表:IXmlDOMNodeList;
节点,
NewNode:IXmlDomNode;
E:Ixmldome元素;
路径查询:字符串;
开始
路径查询:='/DATAPACKET/METADATA/FIELDS';
备忘录2.线条清晰;
XmlDoc:=CoDOMDocument.Create//CreateOleObject('Microsoft.XMLDOM')作为IXMLDOMDocument;
XmlDoc.Async:=False;
LoadXML(Memo1.Lines.Text);
如果xmlDoc.parseError.errorCode为0,则
引发异常.Create('XML加载错误:'+xmlDoc.parseError.reason);
NodeList:=XmlDoc.documentElement.SelectNodes(路径查询);
如果NodeList.length>0,则开始
E:=XMLDoc.createElement('FIELD');
NewNode:=E作为IXMLDomNode;
E.setAttribute('attrname','testField');
E.setAttribute('fieldtype','string');
E.setAttribute('WIDTH','20');
NodeList.item[0]。appendChild(新节点);
结束;
Memo2.Lines.Text:=XMLDoc.documentElement.xml;
备忘录2.行。保存文件(NewFN);
结束;
程序TForm1.LoadNewData;
开始
CDS1.关闭;
CDS1.Fields.Clear;
CDS1.FieldDefs.Clear;
CDS1.LoadFromFile(NewFN);
结束;
程序TForm1.按钮1单击(发送方:TObject);
开始
AddFieldToXML;
加载新数据;
结束;
将新的XML保存到磁盘后,可以通过右键单击CD并使用从MyBase file加载
(对于D7,类似于更高版本),将其加载到IDE中的CD中,然后根据需要创建持久的TField
XML代码是针对D7附带的MSXML.Pas版本的,顺便说一句,我倾向于发布D7的代码,除非q要求更高版本的Delphi。好吧,这取决于。有很多选择。您应该在q中添加一个完整XML文档的最小示例,包括您添加的字段。如果正确执行,这种XML修改通常不会出现问题,尽管您需要清除CD上的任何持久性TFields和TFieldDefs,否则您很可能会报告错误。无论如何,请将其最小化,例如仅使用两个字段的单个测试数据集。不要发布包含30列和500条记录的整个大规模XML数据集。David,比如…?MartynA,明天我将尝试清除持久字段和def。谢谢您是否可以提供任何链接作为示例?我遇到的所有问题似乎都是针对新的XMLdocs的,而不是扩展现有的。@user2765744:嗯,这对解决您的问题有帮助吗?
<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>
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;