Http://www.cnitblog.com/MartinYao/articles/20874.html
Use ADO. Net datasets in Delphi
Abstract
If you 've experimented with Web Services, you might have hit some
Microsoft. NET Based Web Services which return data all right, but it's
In the default XML format from ADO. net. So you end up with some XML
You have no clue what to do with it! This article explains how you can
Take this XML, make sense out of it and even display it in a DB grid.
Scope
I'm not going to explain much about. net, or the ADO. Net XML format.
What I'll talk about is the most probable case you'll encounter. net
Datasets: As XML returned from A. Net Based Web service. If you're
Going to use. Net datasets in some other way, you might want to read
This article to get an idea of how to make your Delphi application
Aware of them.
Hitting the. NET Service
Let's start with a simple. net service, as given in http://services.pagedownweb.com/ZipCodes.asmx
.
I 've used the Web Service importer in file | new | Other | Web Services
And generated the Pascal files. Here's the declaration that looks odd:
rtnZipDSResult = class(TRemotable)
private
Fs_schema: String;
publishedproperty s_schema: Stringread Fs_schema write Fs_schema;
end;
ZipCodesSoap = interface(IInvokable)
['{FEF279A0-29EE-CF0B-FBB2-7DD79A5502CE}']
...
function rtnZipDS(const City_IN: String; const State_IN: String): rtnZipDSResult; stdcall;
...
end;
TheRtnzipds
Function returns a. Net dataset, as XML. Here,S_schema
Of the rtnzipdsresult class is simply the dataset as XML in ADO. Net's
Default format. This means that a. Net client cocould easily get this XML
And show it on a grid or a form-but can we do this with Delphi? Let's
See.
Using the. NET service in Delphi
I 've created a sample form, which looks like this:
Now we 've ve setup the httprio, and the code behindGet zip codes
Button is:
procedure TForm1.Button1Click(Sender: TObject);
begin
(HTTPRIO1 as ZipCodesSoap).rtnZipDS(edtCity.Text, edtState.Text);
end;
I 've also added an event handler on the httprio1.onafterexecute like so:
procedure TForm1.HTTPRIO1AfterExecute(const MethodName: String;
SOAPResponse: TStream);
begin
SOAPResponse.Position := 0;
Memo1.Lines.LoadFromStream(SOAPResponse);
SOAPResponse.Position := 0;
end;
This is only to display the returned content on to a memo so we can
Figure out what to do with it. Here's how the form looks now:
Interpreting the. NET XML
We have to figure out how to get Delphi to use this data. We wowould
Like to have a client data set read the XML so we can display it all in
A grid. For that we'll have to use XDR transforms. No, that's not very
Complicated, and here's how we'll do it.
1. First we're going to save the XML returned into an XML file. I 've saved it as "data. xml ".
2. Run XML mapper from the Tools menu, and open this XML file. Here's a mega screen shot:
3. The zipdata (*) means there's multiple rows of "zipdata"
Available. Columns availabl are zip, city, state, county and areacode.
Let's double-click each one of these to add them to the transformation
And then clickDatapacket from XML
In the create menu. Here's what it all looks like:
4. Save the transformation using file | save | transformation,
"Ziptrans. XTR". Don't try to test the transformation yet. (There's
Bug in Delphi source code that doesn' t like soap namespaces in certain
Elements so it doesn' t show up any data ).
5. We'll now fix this bug. The XTR file is an XML file which you can
Open in any text editor. Open it, and change the first line from:
<SelectEach dest="DATAPACKET/ROWDATA/ROW" from="/soap:Envelope/soap:Body/....">
[Change To]
<SelectEach dest="DATAPACKET/ROWDATA/ROW" from="/Envelope/soap:Body/....">
The reason for this is that Delphi's XML transform provider does
Not like the "Soap:" In the first element of the "from" attribute. That
Might get fixed in some update pack, so this point might not apply
6. We're nearly there. DropTclientdataset
,Txmltransformprovider
AndTdatasource
On the form. Here's what the form looks like now:
Link the grid, the datasource and the clientdataset, and set
Clientdataset's providername to point to the XML transform provider. 7.
SetTransformread. transformationfile
Of the xmltransformproviderZiptrans. XTR
.
8. Now we need to set the data of the XML transform provider at Run
Time. Here's some additional code in the httprio's onafterexecute:
procedure TForm1.HTTPRIO1AfterExecute(const MethodName: String;
SOAPResponse: TStream);
var
XMLDoc: IXMLDocument;
begin
SOAPResponse.Position := 0;
Memo1.Lines.LoadFromStream(SOAPResponse);
ClientDataset1.Active := FALSE;
SOAPResponse.Position := 0;
XMLDoc := NewXMLDocument;
XMLDoc.Encoding := SUTF8;
SOAPResponse.Position := 0;
XMLDoc.LoadFromStream(SOAPResponse);
XMLTransformProvider1.TransformRead.SourceXmlDocument := XMLDoc.GetDOMDocument;
ClientDataset1.Active := TRUE;
end;
You'll notice that we'll ve created an XML document, loaded it from
Received soap stream, and applied the transform to it. The client
Dataset gets data from the provider and displays the data:
That's it!
Amazing.
Thank you.
What's next?
This transformation is very specific to this special service and
XML Schema. So if you know what XML is going to be returned (
Format) Then you can use XML Mapper to generate a transformation
It.
I haven't been able to write a "general" transform that can be
Applied to any. Net returned XML, but if anyone does I 'd love to hear
About It.
Also, why have I used the httprio's onafterexecute, rather
Manipulating the s_schema parameter? There's another bug in Delphi
That doesn't like parameters returned as XML. More revealed in this thread
.
You can download all the code for this project at http://codecentral.borland.com/codecentral/ccweb.exe/listing? Id = 17807
Or at http://www.agnisoft.com/soap/dotnetds.zip
.
Deepak Shenoy
Shenoy@agnisoft.com
) Is a director at Agni Software
,
A software company in India that offers consultancy and offshore
Development Solutions. It might be a while before his hair gets pointy
So he's allowed to understand some technology.
Microsoft found an official saying in China ------ it is not recommended that dataset be directly transmitted as the return value, because it contains a lot of complicated schema and change information, most
The non-. Net Language is difficult to parse. We recommend that you use the dataset. writexml method to return the simplified XML version as a widestring. After testing
It is easy to use in Delphi. in Delphi, you also need to use the XML mapper tool to generate the transfomation (XTR) file in advance.
Delphi7 client code
Bytes ----------------------------------------------------------------------------------------------------------------------------
Unit
Wstestmain;
Interface
Uses
Windows, messages, sysutils, variants, classes, graphics, controls, forms,
Dialogs, invokeregistry, stdctrls, Rio, soaphttpclient, grids, dbgrids,
DB, dbclient, dbtables, provider, xmldom, xmlxform, xmlintf, xmldoc, soapconst;
Type
Tform1 = Class (tform)
Httprio1: thttprio;
Button1: tbutton;
Memo1: tmemo;
Xmltransformprovider1: txmltransformprovider;
Clientdataset1: tclientdataset;
Performance1: tdatasource;
Dbgrid1: TDBGrid;
Procedure
Button1click (Sender: tobject );
Private
{Private Declarations}
Public
{Public declarations}
End;
VaR
Form1: tform1;
Implementation
Uses
Wstestdefine;
{$ R *. DFM}
Procedure
Tform1.button1click (Sender: tobject );
VaR
A: service1soap;
B: widestring;
Xmldoc: ixmldocument;
Begin
A: = httprio1 as service1soap;
B: = A. getpersontable;
Memo1.lines. Add (B );
Clientdataset1.active: = false;
Xmldoc: = newxmldocument;
Xmldoc. encoding: = suf8;
Xmldoc. loadfromxml (B );
Xmltransformprovider1.transformread. sourcexmldocument: = xmldoc. getdomdocument;
Clientdataset1.active: = true;
End;
End.
Bytes ---------------------------------------------------------------------------------------
. Net WebService code
Bytes ---------------------------------------------------------------------------------------
System. Text. stringbuilder strbuilder = new system. Text. stringbuilder ();
Stringwriter writer = new stringwriter (strbuilder );
Dataset. writexml (writer, system. Data. xmlwritemode. ignoreschema );
Return strbuilder. tostring ();
Class
Xmldatasetconvert
{
// Convert the XML Object content string to Dataset
Public
Static
Dataset convertxmltodataset (String
Xmldata)
{
Stringreader stream =Null
;
Xmltextreader reader =Null
;
Try
{
Dataset xmlds =New
Dataset ();
Stream =New
Stringreader (xmldata );
// Load from stream to xmltextreader
Reader =New
Xmltextreader (Stream );
Xmlds. readxml (Reader );
Return
Xmlds;
}
Catch
(System. Exception ex)
{
Throw
Ex;
}
Finally
{
If
(Reader! =Null
)
Reader. Close ();
}
}
// Convert the XML file to Dataset
Public
Static
Dataset convertxmlfiletodataset (String
Xmlfile)
{
Stringreader stream =Null
;
Xmltextreader reader =Null
;
Try
{
Xmldocument xmld =New
Xmldocument ();
Xmld. Load (xmlfile );
Dataset xmlds =New
Dataset ();
Stream =New
Stringreader (xmld. innerxml );
// Load from stream to xmltextreader
Reader =New
Xmltextreader (Stream );
Xmlds. readxml (Reader );
// Xmlds. readxml (xmlfile );
Return
Xmlds;
}
Catch
(System. Exception ex)
{
Throw
Ex;
}
Finally
{
If
(Reader! =Null
)
Reader. Close ();
}
}
// Convert dataset to an XML Object string
Public
Static
String
Convertdatasettoxml (Dataset xmlds)
{
Memorystream stream =Null
;
Xmltextwriter writer =Null
;
Try
{
Stream =New
Memorystream ();
// Load from stream to xmltextreader
Writer =New
Xmltextwriter (stream, encoding. Unicode );
// Use the writexml method to write data to the file.
Xmlds. writexml (writer );
Int
Count = (Int
) Stream. length;
Byte
[] Arr =New
Byte
[Count];
Stream. Seek (0, seekorigin. Begin );
Stream. Read (ARR, 0, count );
Unicodeencoding UTF =New
Unicodeencoding ();
Return
UTF. getstring (ARR). Trim ();
}
Catch
(System. Exception ex)
{
Throw
Ex;
}
Finally
{
If
(Writer! =Null
)
Writer. Close ();
}
}
// Convert dataset to an XML file
Public
Static
Void
Convertdatasettoxmlfile (Dataset xmlds,String
Xmlfile)
{
Memorystream stream =Null
;
Xmltextwriter writer =Null
;
Try
{
Stream =New
Memorystream ();
// Load from stream to xmltextreader
Writer =New
Xmltextwriter (stream, encoding. Unicode );
// Use the writexml method to write data to the file.
Xmlds. writexml (writer );
Int
Count = (Int
) Stream. length;
Byte
[] Arr =New
Byte
[Count];
Stream. Seek (0, seekorigin. Begin );
Stream. Read (ARR, 0, count );
// Return Unicode-encoded text
Unicodeencoding UTF =New
Unicodeencoding ();
Streamwriter Sw =New
Streamwriter (xmlfile );
Sw. writeline ("<? XML version =/"1.0/" encoding =/"UTF-8/"?> "
);
Sw. writeline (UTF. getstring (ARR). Trim ());
Sw. Close ();
}
Catch
(System. Exception ex)
{
Throw
Ex;
}
Finally
{
If
(Writer! =Null
)
Writer. Close ();
}
}
}