getting a DataSet from .Net service

267 views
Skip to first unread message

Stefan T. Hoskuldsson

unread,
Feb 21, 2002, 6:14:03 AM2/21/02
to
Hi, I just put in Update pack 2, very nice job ! All webservices are much
better now !

Is there a way, in D6Ent to connect to a .Net web service that returns a
Dataset ??


TIA
Stefan

Shiv Kumar

unread,
Feb 21, 2002, 11:52:56 AM2/21/02
to
"Stefan T. Hoskuldsson" <ste...@hugtak.is> wrote in message
news:3c74d67c_1@dnews...

> Is there a way, in D6Ent to connect to a .Net web service that returns
a
> Dataset ??
What kind of "Dataset". IN SOAP, there is no "Dataset" type, so it's not
going to be as east as defining a return type as dataset <g>.

It most probably comes as an xml document. If so, you need to know what
this format is and parse the document accordingly or use D6 Ent's new
XML Mapper utility to pump that data into a TClientDataset using a
TXMLTransformProvider.

You might want to take a look at http://www.matlus.com:8080/about for an
example of this.

The dataset is returned (xml) in the typical ADO dataset format. ON the
client, this is used to populate a grid.

--
Shiv Kumar
The Delphi Apostle
http://www.matlus.com
http://www.delphisoap.com


Matt

unread,
Feb 21, 2002, 1:35:25 PM2/21/02
to
How do you get at the xml that would be returned? The type seems to be
defined as a TRemoteable.

"Shiv Kumar" <shivk...@erols.com> wrote in message
news:3c752603_1@dnews...

Shiv Kumar

unread,
Feb 21, 2002, 1:45:34 PM2/21/02
to
Matt,

> How do you get at the xml that would be returned? The type seems to
be
> defined as a TRemoteable.

Sorry, I don't follow. What is this in reference to?

Deepak Shenoy

unread,
Feb 21, 2002, 2:50:22 PM2/21/02
to
> Is there a way, in D6Ent to connect to a .Net web service that returns a
> Dataset ??

Oh yes. I've done it, with a service that returned the dataset as XML.
Except the dratty service didn't encode it's XML, so I,er...had to work
around it...but frankly what do you want to do with it after you have it? (I
don't know either, other than to hand parse it)


--
Deepak Shenoy
Agni Software
http://www.agnisoft.com

Shiv Kumar

unread,
Feb 21, 2002, 3:04:56 PM2/21/02
to
"Deepak Shenoy" <she...@agnisoft.com> wrote in message
news:3c754ef9_2@dnews...

>...but frankly what do you want to do with it after you have it? (I
> don't know either, other than to hand parse it)

Well, then you use the XML Mapper utility to then use an
XMLTransformProvider to pump the data into a TClientDataSet ! <g>.

Deepak Shenoy

unread,
Feb 21, 2002, 3:12:38 PM2/21/02
to
> "Deepak Shenoy" <she...@agnisoft.com> wrote in message
> news:3c754ef9_2@dnews...
> >...but frankly what do you want to do with it after you have it? (I
> > don't know either, other than to hand parse it)
>
> Well, then you use the XML Mapper utility to then use an
> XMLTransformProvider to pump the data into a TClientDataSet ! <g>.

Actually very good idea :) I have still to figure out what that XML mapper
does though ...

The concept of a "dataset" in dotnet is fairly different - a dataset can
consist of multiple "recordsets" and each one can be independent of the
other. In Delphi you have to do master detail if you have multiple
recordsets, and that's one of the only reasons why you can't do a generic
mapper. But hey it would work most of the time I guess.

Shiv Kumar

unread,
Feb 21, 2002, 3:22:53 PM2/21/02
to
"Deepak Shenoy" <she...@agnisoft.com> wrote in message
news:3c755431_2@dnews...

> > "Deepak Shenoy" <she...@agnisoft.com> wrote in message
> > news:3c754ef9_2@dnews...
> Actually very good idea :) I have still to figure out what that XML
mapper
> does though ...

It's quite intuitive actually. Hey I figured it out (That's probably the
one and only time I've actually played with it), anyone can!

> The concept of a "dataset" in dotnet is fairly different - a dataset
can
> consist of multiple "recordsets" and each one can be independent of
the
> other. In Delphi you have to do master detail if you have multiple
> recordsets, and that's one of the only reasons why you can't do a
generic
> mapper. But hey it would work most of the time I guess.

Yes, a "dataset" is not a Delphi dataset in .NET

a recordset is a Dataset (This has always been the case with OLEDB)

A would guess, that a dataset may contain one or more "recordsets" (that
is the format used by ADO for a recordset).

So it should be easy to do even with the mapper.

At the same time, given that the format of a "dataset" is standard, it
will be a one time effort to build a parsing routine to get the job done
no?

"Deepak Shenoy" <she...@agnisoft.com> wrote in message

news:3c755431_2@dnews...

Deepak Shenoy

unread,
Feb 21, 2002, 3:30:23 PM2/21/02
to
> > Actually very good idea :) I have still to figure out what that XML
> mapper
> > does though ...
>
> It's quite intuitive actually. Hey I figured it out (That's probably the
> one and only time I've actually played with it), anyone can!

You're underestimating yourself :) I will give it a shot tomorrow though (q
to self: why am I up so late?)

> At the same time, given that the format of a "dataset" is standard, it
> will be a one time effort to build a parsing routine to get the job done
> no?

I think it would...though I'm not sure about the released version of .NET.
I'll have to try with and without the schema and with some complicated stuff
too...and that too after I've figured out that XML mapper thingy...anyone
who's already taken a shot at this?

Matt

unread,
Feb 21, 2002, 5:02:26 PM2/21/02
to
Here is what we are talking about:

Use the famous ZipCode example from xmethods.com.

WSDL: http://services.pagedownweb.com/ZipCodes.asmx?wsdl

Specifically, look at the rtnZipDS method. The WSDL importer defines the
result as a type "rtnZipDSResult", which is of type TRemotable and has only
one property: "s_schema". When the function returns, the s_schema does not
have anything in it.

So my question is how do you get to the underlying xml that I assume is
returned? .Net can load it into their ADO.NET Dataset. I would just like
to get at the xml. There does not seem to be a property to get at the xml as
a string or a IXMLDocument. How do you apply a TransformProvider to the
rtnZipDSResult type?

Thanks.

"Deepak Shenoy" <she...@agnisoft.com> wrote in message

news:3c75585a_2@dnews...

Shiv Kumar

unread,
Feb 21, 2002, 5:51:22 PM2/21/02
to
Matt,

There is a problem with accessing this WebService. I'm not sure if this
is a D6 issue or something that D6 does not support as yet.

The service does in fact return data (a whole bunch of xml), but the
'scheme' property returns a blank.

The XML it return look like this:

<xs:schema id="NewDataSet" xmlns=""
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="NewDataSet" msdata:IsDataSet="true">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element name="DATA">
<xs:complexType>
<xs:sequence>
<xs:element name="County" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
<NewDataSet xmlns="">
<DATA diffgr:id="DATA1"
msdata:rowOrder="0"><County>Accomack</County></DATA>
<DATA diffgr:id="DATA2"
msdata:rowOrder="1"><County>Albemarle</County></DATA>
<DATA diffgr:id="DATA3" msdata:rowOrder="2"><County>Alexandria
City</County></DATA>
<DATA diffgr:id="DATA4"
msdata:rowOrder="3"><County>Alleghany</County></DATA>
<DATA diffgr:id="DATA5"
msdata:rowOrder="4"><County>Amelia</County></DATA>
<DATA diffgr:id="DATA6"
msdata:rowOrder="5"><County>Amherst</County></DATA>
</NewDataSet>
</diffgr:diffgram>

Bruneau?

Deepak Shenoy

unread,
Feb 22, 2002, 4:11:38 AM2/22/02
to
> Use the famous ZipCode example from xmethods.com.
>
> WSDL: http://services.pagedownweb.com/ZipCodes.asmx?wsdl
>
> Specifically, look at the rtnZipDS method. The WSDL importer defines the
> result as a type "rtnZipDSResult", which is of type TRemotable and has
only
> one property: "s_schema". When the function returns, the s_schema does
not
> have anything in it.
>
> So my question is how do you get to the underlying xml that I assume is
> returned? .Net can load it into their ADO.NET Dataset. I would just like
> to get at the xml. There does not seem to be a property to get at the xml
as
> a string or a IXMLDocument. How do you apply a TransformProvider to the
> rtnZipDSResult type?

I think I've got this licked. I've uploaded an attachment to the attachments
group, which does the necessary transformation.

I think I've got the hang of this XML mapper thingy too - found a bug in
TXMLTransform also. IN XmlUtil there's a function called "SelectNode' THat
is called by the TXMLTransform.Transform() :

SrcNode := SelectNode(SrcNode, From);

Here if "From" is of the type "\soap:Envelope\soap:Body\..." it fails. Why?
Because the FIRST node to be selected, "soap:Envelope" fails the following
test in SelectNode:

if ExtractLocalName(Node.NodeName) = Tags.Strings[0] then

The reason is that here, Node.NodeName is "soap:Envelope", but the
ExtractLocalName chops this to "Envelope" (removes the "soap:") Now
Tags.Strings[0] is still "soap:Envelope" so the test fails. THis probalby
has a whole lot of dependencies, so I'm not sure of the best solution, but
what I did was simply changed the transform XML to use "\Envelope" instead.
But maybe this change might work:

if ExtractLocalName(Node.NodeName) = ExtractLocalName(Tags.Strings[0])
then

Does this sound correct?

Btw, the attachment will also be available at
http://www.agnisoft.com/soap/dotnetds.zip (the attachements group is quite
volatile)

Jean-Marie Babet

unread,
Feb 22, 2002, 2:46:50 PM2/22/02
to
Matt, Shiv...

Thanks for the report. I just investigated this service a little and here
are my findings:

There's a flaw in the importer that does not understand "ref" namespace
properly. The WSDL describes the rtnCountyDSResult as:

<s:element minOccurs="0" maxOccurs="1" name="rtnCountyDSResult">
<s:complexType>
<s:sequence>
<s:element ref="s:schema" />
<s:any />
</s:sequence>
</s:complexType>
</s:element>

NOTE -- ref="s:schema".


Now the WSDL importer gives:


rtnZipDSResult = class(TRemotable)
private
Fs_schema: WideString;
published
property s_schema: WideString read Fs_schema write Fs_schema;
end;

NOTE -- property s_schema.


The net result is that the SOAP runtime looks for a node named "s_schema"
instead of one with the localname of "schema". This is easy to fix: just
update the generated structure to read:

rtnZipDSResult = class(TRemotable)
private
Fs_schema: WideString;
published
property schema: WideString read Fs_schema write Fs_schema;
end;


However, once you do this, you'll hit another problem. The code that
deserializes a string invokes Node.Text on the node. For nodes of type
"xds:string" this works fine. However, we don't have a TEXT node: we have a
whole XML result. The reference to Node.Text will cause the DOM to complain
that this is not a Text node.

I've remedied with the following workaround.

Find the routine 'LoadObject' in OpToSOAPDomConv.pas and look for the
following line:

SetObjectPropFromText(Instance, PropList[I], ChildNode.Text);

That's where we're loading the property with the node's text. I've changed
my local copy to the following instead:

begin
try
SetObjectPropFromText(Instance, PropList[I], ChildNode.Text);
except
SetObjectPropFromText(Instance, PropList[I], ChildNode.XML);
end;
end;

Not exactly elegant but safe for now (Ideal would be to check the node type;
I'll do that after I run some tests against various node types).

Once the above fixes applied, I was able to retrieve the XML packet using
something like this:


procedure TForm1.ZipDSClick(Sender: TObject);
var
rtnZip: rtnZipDSResult;
Service: ZipCodesSoap;
begin
Service := GetZipCodesSoap;
rtnZip := Service.rtnZipDS(CityIn.Text, StateIn.Text);
Memo1.Text := rtnZip.schema;
end;

The Memo1 ends up with the following with I send 'Redmond' and 'WA':

<xs:schema id="NewDataSet" xmlns=""
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"><xs:element
name="NewDataSet" msdata:IsDataSet="true"><xs:complexType><xs:choice
maxOccurs="unbounded"><xs:element

name="ZIPDATA"><xs:complexType><xs:sequence><xs:element name="Zip"
type="xs:string" minOccurs="0"/><xs:element name="City" type="xs:string"
minOccurs="0"/><xs:element name="State" type="xs:string"
minOccurs="0"/><xs:element name="County" type="xs:string"
minOccurs="0"/><xs:element name="AreaCode" type="xs:string"


minOccurs="0"/></xs:sequence></xs:complexType></xs:element></xs:choice></xs:
complexType></xs:element></xs:schema>


Now, about the data?? Well, back to the WSDL:


<s:element minOccurs="0" maxOccurs="1" name="rtnCountyDSResult">
<s:complexType>
<s:sequence>
<s:element ref="s:schema" />
<s:any />
</s:sequence>
</s:complexType>
</s:element>

After the "s:scheme" ref above there's an <s:any />. Well, that's a problem
for the Delphi approach to serialization because it needs a name in order to
pick up the data coming back. I cheated because (thanks Shiv) I know that
the node coming back is "<diffgr:diffgram " etc. etc.

So next I updated my rtnZipDSResult to read:

rtnZipDSResult = class(TRemotable)
private
Fs_schema: WideString;
FData: WideString;
published
property schema: WideString read Fs_schema write Fs_schema;
property diffgram: WideString read FData write FData;
end;

With that, then I'm able to pick up both the schema and the data:


procedure TForm1.ZipDSClick(Sender: TObject);
var
rtnZip: rtnZipDSResult;
Service: ZipCodesSoap;
begin
Service := GetZipCodesSoap;
rtnZip := Service.rtnZipDS(CityIn.Text, StateIn.Text);
Memo1.Text := rtnZip.schema;
Memo2.Text := rtnZip.diffgram;
end;

Memo2 then ends up with the following after I click the button:

<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"><NewDataSet

xmlns=""><ZIPDATA diffgr:id="ZIPDATA1"
msdata:rowOrder="0"><Zip>98052</Zip><City>Redmond</City><State>WA</State><Co
unty>King</County><AreaCode>206</AreaCode></ZIPDATA><ZIPDATA
diffgr:id="ZIPDATA2"
msdata:rowOrder="1"><Zip>98053</Zip><City>Redmond</City><State>WA</State><Co
unty>King</County><AreaCode>206</AreaCode></ZIPDATA><ZIPDATA
diffgr:id="ZIPDATA3"
msdata:rowOrder="2"><Zip>98073</Zip><City>Redmond</City><State>WA</State><Co
unty>King</County><AreaCode>206</AreaCode></ZIPDATA></NewDataSet></diffgr:di
ffgram>


I can send you the sample project I played with to investigate the above.

I'll need to spend more time to investigate some way where I can flag a
published member as "maps to the next childnode irrespective of whether the
name matches or not". I'll also clean up the Text vs. XML property. I don't
like the approach mentioned above at all.

More to come on this...


Bruneau.


Deepak Shenoy

unread,
Feb 22, 2002, 3:03:06 PM2/22/02
to
> After the "s:scheme" ref above there's an <s:any />. Well, that's a
problem
> for the Delphi approach to serialization because it needs a name in order
to
> pick up the data coming back. I cheated because (thanks Shiv) I know that
> the node coming back is "<diffgr:diffgram " etc. etc.

All dotnet datasets will come back as that <diffgr:diffgram... :)

> I'll need to spend more time to investigate some way where I can flag a
> published member as "maps to the next childnode irrespective of whether
the
> name matches or not".

That will be NEAT. Will look forward to hearing more..

> I'll also clean up the Text vs. XML property. I don't
> like the approach mentioned above at all.

True - it has an exception raised which is not good because it'll break
while debugging and then there'll be a whole lot of more complaints. Would
you change the text property to return XML?

Thanks,
Deepak

Shiv Kumar

unread,
Feb 22, 2002, 10:50:38 PM2/22/02
to
Bruneau,

Thanks for the quick response and update!

On the .NET "dataset" front, would it make sense to "support" their
concept of "dataset" in some fashion? I'm not up to speed with the
various "standards" out there, but I'm sure with the way Microsoft
works, it would be beneficial for Delphi to "support" this kind of
thing. What I mean is, once this "fix" is in place, we could go a step
further and have the ability to define a .NET Dataset type <go>.

Reply all
Reply to author
Forward
0 new messages