Thread

Posted on Mon Apr 28 23:43:56 2008 by sacharya
SOAP::WSDL noob question about namespace prefixing

OK, I saw a previous post in the forums about this, but I think I need a more detailed example on how exactly to achieve what I need to do.

So I have a web service that I've deployed in a Sun Glassfish App Server (the service itself uses the JAXWS 2.x API stack). For brevity's sake, I'm going to avoid posting the whole WSDL here, though I can do that if necessary.

But basically, I need to do the equivalent of the following code, only I'd like do do this using SOAP::WSDL instead of SOAP::Lite (because the latter has other issues with the return values that I have been unable to figure out how to deal with):

my $soap = SOAP::Lite ->ns('http://myservice.mycompany.com/','ns2') ->proxy("http://servername.mycompany.com/ServiceLocation/MyService") ->on_fault(sub { my($soap, $res) = @_; die "error: ", ref $res ? $res->faultstring : $soap->transport->status, "\n"; }); my $returned = $soap->call(SOAP::Data->name('ns2:myWebServiceMethod') => SOAP::Data->name('arg0')->value('param1')->type(''), SOAP::Data->name('arg1')->value('param2')->type('') );

Effectively, I've got a SOAP method that takes two input parameters and returns a list of strings.

So the corresponding SOAP::WSDL code I am using (after having generated the stubs using wsdl2perl.pl) looks like this:

use strict; use SOAP::Lite +trace => 'debug'; use MyInterfaces::MyService::MyPort; my $service = MyInterfaces::MyService::MyPort->new(); my $result = $service->myWebServiceMethod({ arg0 => "param1", arg1 => "param2" }); die $result if not $result; print "\n\n\n$result\n";

However, this generates a SOAP request that looks like the following, on the wire:

<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" > <SOAP-ENV:Body> <myWebServiceMethod xmlns="http://myservice.mycompany.com/"> <arg0>param1</arg0> <arg1>param2</arg1> </myWebServiceMethod> </SOAP-ENV:Body> </SOAP-ENV:Envelope>

However, unfortunately, the JAXWS API stack seems to require a namespace prefix on only on the method name element, as opposed to the default namespace which is applied to the method name element via the xmlns attribute.

So, to clarify, my web service only seems to return data when the SOAP request looks like this:

<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns2="http://myservice.mycompany.com/" > <SOAP-ENV:Body> <ns2:myWebServiceMethod> <arg0>param1</arg0> <arg1>param2</arg1> </ns2:myWebServiceMethod> </SOAP-ENV:Body> </SOAP-ENV:Envelope>

I can get the web service to return data correctly using SOAP::Lite, though, like I said, I am having trouble with getting SOAP::Lite to properly deserialize the list of strings that my method returns.

So, I was hoping SOAP::WSDL would be able to do a better job with data structure deserialization - only, I can't even get it to form the SOAP request the way it needs to be, in order for my service to actually return anything.

Any help would be *GREATLY* appreciated, I am pretty new to working with these packages in Perl (let alone working with object-oriented Perl).

Much thanks to anyone who can assist!!

Regards,
Sankalp

Direct Responses: 7791 | Write a response
Posted on Tue Apr 29 13:35:16 2008 by noah in response to 7786
Re: SOAP::WSDL noob question about namespace prefixing

As I understand it, you need to write your own serializer to do this; I wound up doing this:

MySerializer.pm:

package MySerializer; use strict; use warnings; use SOAP::WSDL::Serializer::XSD; use base 'SOAP::WSDL::Serializer::XSD'; sub serialize { my ($self, $args_of_ref) = @_; my $xml = $self->SUPER::serialize($args_of_ref); # # insert the xmlns:ns2 namespace definition $xml =~ s#>#xmlns:ns2=\"http://services.example.com/\">#; return $xml; } sub serialize_body { my ($self, $name, $data, $opt) = @_; # # set the namespace prefix $data->__set_name("ns2:$name"); # # ensure that the namespace isn't set as part of the API call no warnings 'redefine'; *MyElements::getElementId::get_xmlns = sub { '' }; return $self->SUPER::serialize_body($name, $data, $opt); } 1;

get_element_id.pl:

#!/usr/bin/perl use strict; use warnings; use MyInterfaces::MyService::MyServicePort; use MySerializer; my $svc = MyInterfaces::MyService::MyServicePort->new(); $svc->set_serializer('MySerializer'); my $res = $svc->getElementId(); die $res->get_faultstring unless $res; print $res;
This may or may not be the Right Way(tm) to do this, but it works for me. Hope this helps.
Direct Responses: 7797 | Write a response
Posted on Wed Apr 30 01:09:21 2008 by sacharya in response to 7791
Re: SOAP::WSDL noob question about namespace prefixing
Thanks so much, Noah! I got the interop working with my Java web service, after countless hours of much frustration, thanks to your help! :)
Write a response