数据库转换成XML<br>procedure DatasetToXML(Dataset: TDataset; FileName: string); <br><br>unit DS2XML; <br><br>interface <br><br>uses <br> Classes, DB; <br><br>procedure DatasetToXML(Dataset: TDataset; FileName: string); <br><br>implementation <br><br>uses <br> SysUtils; <br><br>var <br> SourceBuffer: PChar; <br><br>procedure WriteString(Stream: TFileStream; s: string); <br>begin <br> StrPCopy(SourceBuffer, s); <br> Stream.Write(SourceBuffer[0], StrLen(SourceBuffer)); <br>end; <br><br>procedure WriteFileBegin(Stream: TFileStream; Dataset: TDataset); <br><br> function XMLFieldType(fld: TField): string; <br> begin <br> case fld.DataType of <br> ftString: Result := '"string" WIDTH="' + IntToStr(fld.Size) + '"'; <br> ftSmallint: Result := '"i4"'; //?? <br> ftInteger: Result := '"i4"'; <br> ftWord: Result := '"i4"'; //?? <br> ftBoolean: Result := '"boolean"'; <br> ftAutoInc: Result := '"i4" SUBTYPE="Autoinc"'; <br> ftFloat: Result := '"r8"'; <br> ftCurrency: Result := '"r8" SUBTYPE="Money"'; <br> ftBCD: Result := '"r8"'; //?? <br> ftDate: Result := '"date"'; <br> ftTime: Result := '"time"'; //?? <br> ftDateTime: Result := '"datetime"'; <br> else <br> end; <br> if fld.Required then <br> Result := Result + ' required="true"'; <br> if fld.Readonly then <br> Result := Result + ' readonly="true"'; <br> end; <br><br>var <br> i: Integer; <br>begin <br> WriteString(Stream, ' ' + <br> ''); <br> WriteString(Stream, ''); <br><br> {write th metadata} <br> with Dataset do <br> for i := 0 to FieldCount-1 do <br> begin <br> WriteString(Stream, ''); <br> end; <br> WriteString(Stream, ''); <br> WriteString(Stream, ''); <br> WriteString(Stream, ''); <br>end; <br><br>procedure WriteFileEnd(Stream: TFileStream); <br>begin <br> WriteString(Stream, ''); <br>end; <br><br>procedure WriteRowStart(Stream: TFileStream; IsAddedTitle: Boolean); <br>begin <br> if not IsAddedTitle then <br> WriteString(Stream, 'end; <br><br>procedure WriteRowEnd(Stream: TFileStream; IsAddedTitle: Boolean); <br>begin <br> if not IsAddedTitle then <br> WriteString(Stream, '/>'); <br>end; <br><br>procedure WriteData(Stream: TFileStream; fld: TField; AString: ShortString); <br>begin <br> if Assigned(fld) and (AString <> '') then <br> WriteString(Stream, ' ' + fld.FieldName + '="' + AString + '"'); <br>end; <br><br>function GetFieldStr(Field: TField): string; <br><br> function GetDig(i, j: Word): string; <br> begin <br> Result := IntToStr(i); <br> while (Length(Result) < j) do <br> Result := '0' + Result; <br> end; <br><br>var Hour, Min, Sec, MSec: Word; <br>begin <br> case Field.DataType of <br> ftBoolean: Result := UpperCase(Field.AsString); <br> ftDate: Result := FormatDateTime('yyyymmdd', Field.AsDateTime); <br> ftTime: Result := FormatDateTime('hhnnss', Field.AsDateTime); <br> ftDateTime: begin <br> Result := FormatDateTime('yyyymmdd', Field.AsDateTime); <br> DecodeTime(Field.AsDateTime, Hour, Min, Sec, MSec); <br> if (Hour <> 0) or (Min <> 0) or (Sec <> 0) or (MSec <> 0) then <br> Result := Result + 'T' + GetDig(Hour, 2) + ':' + GetDig(Min, 2) + ':' + GetDig(Sec, 2) + GetDig(MSec, 3); <br> end; <br> else <br> Result := Field.AsString; <br> end; <br>end; <br><br> <br><br>procedure DatasetToXML(Dataset: TDataset; FileName: string); <br>var <br> Stream: TFileStream; <br> bkmark: TBookmark; <br> i: Integer; <br>begin <br> Stream := TFileStream.Create(FileName, fmCreate); <br> SourceBuffer := StrAlloc(1024); <br> WriteFileBegin(Stream, Dataset); <br><br> with DataSet do <br> begin <br> DisableControls; <br> bkmark := GetBookmark; <br> First; <br><br> {write a title row} <br> WriteRowStart(Stream, True); <br> for i := 0 to FieldCount-1 do <br> WriteData(Stream, nil, Fields.DisplayLabel); <br> {write the end of row} <br> WriteRowEnd(Stream, True); <br><br> while (not EOF) do <br> begin <br> WriteRowStart(Stream, False); <br> for i := 0 to FieldCount-1 do <br> WriteData(Stream, Fields, GetFieldStr(Fields)); <br> {write the end of row} <br> WriteRowEnd(Stream, False); <br><br> Next; <br> end; <br><br> GotoBookmark(bkmark); <br> EnableControls; <br> end; <br><br> WriteFileEnd(Stream); <br> Stream.Free; <br> StrDispose(SourceBuffer); <br>end; <br><br>end. <br><br><br> <br><br><br> 生成XML文件。<br> 我使用下面的转换方法:<br> I . XML文件的根名与表名相同(本例就是country)。<br> II. 每条来自于表的记录由<record></record>标记区分。<br> III. 每个来自于表的数据由其字段名标记加以区分。<br> <br> - <country> <br> - <Records> <br> <Name>Argentina</Name> <br> <Capital>Buenos Aires</Capital> <br> <Continent>South America</Continent> <br> <Area>2777815</Area> <br> <Population>32300003</Population> <br> </Records> <br> . <br> . <br> . <br> </country> <br> <br> 建立一个新的应用程序。放置一个Button和Table构件于主窗体上。设置表属性如下:<br> DatabaseName : DBDEMOS <br> Name : Table1 <br> TableName : country (Remove the extention ".db") <br> Active : True <br> <br> 选择 Project/Import Type library。将会弹出 "Import Type Library" 对话框。从列表中选择 "Microsoft XML,Version <br> 2.0(version 2.0)" 然后点击 "Create Unit" 按钮。将会有一个 MSXML_TLB 单元加入你的工程.请将 MSXML_TLB 加入你要引用的单元的接口部分。然后在变量部分声明如下变量:<br> DataList : TStringlist; <br> doc : IXMLDOMDocument; <br> root,child,child1 : IXMLDomElement; <br> text1,text2 : IXMLDOMText; <br> nlist : IXMLDOMNodelist; <br> dataRecord : String; <br> <br> 添加makeXml函数到你的单元。它将通过读取DBDEMOS中contry表中的数据生成一个XML文件。<br> function TForm1.makeXml(table:TTable):Integer; <br> var <br> i : Integer; <br> xml,temp : String; <br> begin <br> try <br> table.close; <br> table.open; <br> xml := table.TableName; <br> doc := CreateOleObject('Microsoft.XMLDOM') as IXMLDomDocument; <br> //Set the root name of the xml file as that of the table name. <br> //In this case "country" <br> root := doc.createElement(xml); <br> doc.appendchild(root); <br> //This while loop will go through the entaire table to generate the xml file <br> while not table.eof do <br> begin <br> //adds the first level children , Records <br> child:= doc.createElement('Records'); <br> root.appendchild(child); <br> for i:=0 to table.FieldCount-1 do <br> begin <br> //adds second level children <br> child1:=doc.createElement(table.Fields.FieldName); <br> child.appendchild(child1); <br> //Check field types <br> case TFieldType(Ord(table.Fields.DataType)) of <br> ftString: <br> begin <br> if Table.Fields.AsString ='' then <br> temp :='null' //Put a default string <br> else <br> temp := table.Fields.AsString; <br> end; <br> <br> ftInteger, ftWord, ftSmallint: <br> begin <br> if Table.Fields.AsInteger > 0 then <br> temp := IntToStr(table.Fields.AsInteger) <br> else <br> temp := '0'; <br> end; <br> ftFloat, ftCurrency, ftBCD: <br> begin <br> if table.Fields.AsFloat > 0 then <br> temp := FloatToStr(table.Fields.AsFloat) <br> else <br> temp := '0'; <br> end; <br> ftBoolean: <br> begin <br> if table.Fields.Value then <br> temp:= 'True' <br> else <br> temp:= 'False'; <br> end; <br> ftDate: <br> begin <br> if (not table.Fields.IsNull) or <br> (Length(Trim(table.Fields.AsString)) > 0) then <br> temp := FormatDateTime('MM/DD/YYYY', <br> table.Fields.AsDateTime) <br> else <br> temp:= '01/01/2000'; //put a valid default date <br> end; <br> ftDateTime: <br> begin <br> if (not table.Fields.IsNull) or <br> (Length(Trim(table.Fields.AsString)) > 0) then <br> temp := FormatDateTime('MM/DD/YYYY hh:nn:ss', <br> Table.Fields.AsDateTime) <br> else <br> temp := '01/01/2000 00:00:00'; //Put a valid default date and time <br> end; <br> ftTime: <br> begin <br> if (not table.Fields.IsNull) or <br> (Length(Trim(table.Fields.AsString)) > 0) then <br> temp := FormatDateTime('hh:nn:ss', <br> table.Fields.AsDateTime) <br> else <br> temp := '00:00:00'; //Put a valid default time <br> end; <br> end; <br> // <br> child1.appendChild(doc.createTextNode(temp)); <br> end; <br> table.Next; <br> end; <br> doc.save(xml+'.xml'); <br> memo1.lines.Append(doc.xml); <br> Result:=1; <br> except <br> on e:Exception do <br> Result:=-1; <br> end; <br> end; <br> <br> 在Button1的onclick事件中调用上面的函数<br> procedure TForm1.Button1Click(Sender: TObject); <br> begin <br> if makeXml(table1)=1 then <br> showmessage('XML Generated') <br> else <br> showmessage('Error while generating XML File'); <br> end; <br> <br> 如果你用IE 5.0(或以上版本)打开生成的country.xml文件,它看起来会成下面的样子<br> - <country> <br> - <Records> <br> <Name>Argentina</Name> <br> <Capital>Buenos Aires</Capital> <br> <Continent>South America</Continent> <br> <Area>2777815</Area> <br> <Population>32300003</Population> <br> </Records> <br> - <Records> <br> <Name>Bolivia</Name> <br> <Capital>La Paz</Capital> <br> <Continent>South America</Continent> <br> <Area>1098575</Area> <br> <Population>7300000</Population> <br> </Records> <br> . <br> . <br> . <br> - <Records> <br> <Name>Venezuela</Name> <br> <Capital>Caracas</Capital> <br> <Continent>South America</Continent> <br> <Area>912047</Area> <br> <Population>19700000</Population> <br> </Records> <br> </country> <br> <br> 插入数据<br> <br> 你已经将country表中存在的数据生成了XML文件。因此在这个XML文件中的数据就与country表中是一样的。如果你想将XML文件中的数据插入进country表中又不想删除原来存在的数据的话,将会有主键冲突的错误出现。因此必须先将country表中已经存在的数据删除掉。<br> 添加另一个按钮和一个memo构件于主窗体。在button2的onclick事件中添加如下代码.memo用来显示数据插入中的状态(成功/失败)。<br> procedure TForm1.Button2Click(Sender: TObject); <br> var <br> i,ret_val,count:Integer; <br> strData:String; <br> begin <br> //Before inserting data in to the country table,make sure that the data in <br> //the generated xml file(country.xml) and country table(DBDEMOS) are <br> //different. <br> try <br> count:=1; <br> DataList:=TStringList.Create; <br> memo1.Clear; <br> doc := CreateOleObject('Microsoft.XMLDOM') as IXMLDomDocument; <br> //Load country.xml file <br> doc.load('country.xml'); <br> nlist:=doc.getElementsByTagName('Records'); <br> memo1.lines.append('Table Name :country'); <br> memo1.lines.append('---------------------'); <br> for i:=0 to nlist.Get_length-1 do <br> begin <br> travelChildren(nlist.Get_item(i).Get_childNodes); <br> //Removes the first character(,) from dataRecord <br> strData:=copy(dataRecord,2,length(dataRecord)); <br> memo1.lines.append(strData); <br> dataRecord:=''; <br> ret_val:=insertintotable(Datalist); <br> if ret_val=1 then <br> memo1.lines.append('Data inserted successfully.............!') <br> else if ret_val=-1 then <br> memo1.lines.append('Error while updating.....Try again.....!'); <br> memo1.lines.append('=============================================' <br> +'==(Record no. :'+inttostr(count)+')'); <br> DataList.Clear; <br> count:=count+1; <br> end; <br> except <br> on e:Exception do <br> Showmessage(e.message); <br> end; <br> end; <br> <br> nlist(refer above program) contains a list of nodes.In our case the first node list is... <br> <br> <Records> <br> <Name>Argentina</Name> <br> <Capital>Buenos Aires</Capital> <br> <Continent>South America</Continent> <br> <Area>2777815</Area> <br> <Population>32300003</Population> <br> </Records> <br> <br> <br> 我们传送此节点列表给一个递归函数,travelchildren。它将递归地沿着节点列表查找文本数据,并将此数据加入TStringList(Datalist)变量中。当完成第一轮后,Datalist中将会包含字符串 Argentina,Buenos Aires,South America,2777815,32300003.最后我们将此stringlist传送给函数 insertintotable,它将完成将一条记录插入 country 表的工作。重复此过程即可完成整个XML文件数据的插入工作。<br> procedure TForm1.travelChildren(nlist1:IXMLDOMNodeList); <br> var <br> j:Integer; <br> temp:String; <br> begin <br> for j:=0 to nlist1.Get_length-1 do <br> begin <br> //node type 1 means an entity and node type 5 means EntityRef <br> if((nlist1.Get_item(j).Get_nodeType= 1) or (nlist1.Get_item(j).Get_nodeType=5)) then <br> travelChildren(nlist1.Get_item(j).Get_childNodes) <br> //node Type 3 means a text node,ie you find the data <br> else if(nlist1.Get_item(j).Get_nodeType=3) then <br> begin <br> temp:= trim(nlist1.Get_item(j).Get_nodeValue); <br> dataRecord:=dataRecord+','+temp; //this is for displaying a single record on the memo <br> DataList.Add(temp); //Datalist will contain one record after completing one full travel through the node list <br> end <br> end; <br> end; <br> <br> function TForm1.insertintotable(stpt:TStringList):Integer; <br> var <br> i:Integer; <br> begin <br> table1.close; <br> table1.open; <br> table1.Insert; <br> for i := 0 to stpt.Count - 1 do <br> begin <br> table1.Fields.AsVariant:= stpt; <br> end; <br> try <br> table1.post; <br> result:=1; <br> except <br> on E:Exception do <br> result:=-1; <br> end; <br> end; <br> <br> 结论:<br> 你可以将此程序推广至任何数据库,由此数据可以通过XML文件在网络(即使是internet)中传输并在其实终端上更新数据库。我在生成XML文件中还未考虑特殊字符如 &,<,>,',''等等。你可以在生成带这些字符的XML文件时作适合自己需要的改变.