I have imported a WSDL and use it to send a SOAP request. It looks like this:
OMG! It took lots of coffee and plenty of sleep depravation but I managed to solve my problem! It's reasonable simple too...
First I import the WSDL, as expected. This will generate several TRemotable classes. Then, for each TRemotable which needs a different namespace, I override the ObjectToSOAP() method! (And include XMLIntf to the WSDL source.) In my case with code like this for several of the remotable types:
function AL2.ObjectToSOAP( RootNode, ParentNode: IXMLNode; const ObjConverter: IObjConverter; const NodeName, NodeNamespace, ChildNamespace: InvString; ObjConvOpts: TObjectConvertOptions; out RefID: InvString ): IXMLNode;
begin
Result := inherited ObjectToSOAP( RootNode, ParentNode, ObjConverter, NodeName, '', '', ObjConvOpts, RefID );
end;
Which worked in Delphi XE. In Delphi 2007 I had to use units XMLIntf and XMLDoc plus this code on the input type:
function ContractdocumentInType.ObjectToSOAP(RootNode, ParentNode: IXMLNode; const ObjConverter: IObjConverter; const Name, URI: InvString; ObjConvOpts: TObjectConvertOptions; out RefID: InvString): IXMLNode;
procedure AlterChildren(Child: IXMLNode);
var
I: Integer;
begin
if (Child.NodeType = ntElement) then Child.SetAttributeNS('xmlns', '', '');
for I := 0 to Pred(Child.ChildNodes.Count) do
AlterChildren(Child.ChildNodes[I]);
end;
begin
Result := inherited ObjectToSOAP(RootNode, ParentNode, ObjConverter, Name, '', ObjConvOpts, RefID);
AlterChildren(Result);
end;
It is a hack, in my opinion. But it's not a very dirty one. It's a bit of experimenting, capturing the SOAP requests and responses to check their content and to see if it uses the proper namespaces. Unfortunately, Delphi XE does a far better job at this than Delphi 2007.
Still, I keep this Q open for any better solutions...
Btw, to add the col:
to the output, I also had to change this line in the WSDL RemClassRegistry.RegisterXSClass(Calculate, 'http://colan.ogconnect.service.wzp/', 'Calculate');
to this: RemClassRegistry.RegisterXSClass(Calculate, 'http://colan.ogconnect.service.wzp/', 'cal:Calculate');
. The result then becomes
. Ont more thing needs to be done, though: moving that xmlns:cal
to the xml header. But as it is now, it works for me.
Another note: for the WSDL I used the following settings: 'One Outparam is return', 'Unwind literal params', 'Generate destructors', 'Warning comments', 'emit literal types', 'Map string to widestring'. Other options are: 'Generate verbose information about types and interfaces', 'Ignore porttypes with HTTP Bindings', 'Validate enumeration members', 'Import fault types', 'Import header types', 'Process included and imported schemas', 'Generate class alias as class types', 'Allow Out parameters' and 'Process nillable and optional elements'. The emit literal types was practical because it generates a class around the single method that I was calling. Unfortunately, this won't help much either, although the class would help you to modify the SOAP request on the upper level within the envelope by overriding the ObjectToSOAP() method.
Creation of the envelope itself is in the SOAPEnv unit and it's used in the OPToSOAPDomConv unit. Unfortunately, I haven't found an easy method to access the envelope itself to alter the header to add this additional namespace. Then again, I could override the TSOAPDomConv class with my own version that does add the additional namespace. But the code is working for me now, and as my father told me, when he learned me to program: never fix anything that isn't broken.