Thread

Posted on Mon Apr 21 16:56:51 2008 by noah
mucking with namespaces
I need to interface with a SOAP server which doesn't accept the following format:
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> <getElement xmlns="http://services.company.com/"> <elementId>12345</elementId> </getElement> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Instead, it requires this:
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="http://services.company.com/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> <ns2:getElement> <elementId>12345</elementId> </ns2:getElement> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
How do I do this using SOAP::WSDL? Do I create my own serializer class, or is there another way? Thanks, Noah
Direct Responses: 7716 | Write a response
Posted on Mon Apr 21 23:39:20 2008 by mkutter in response to 7714
Re: mucking with namespaces
The latter actually means this:
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://sch +emas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> <getElement xmlns="http://services.company.com/"> <elementId xmlns="">12345</elementId> </getElement> </SOAP-ENV:Body> </SOAP-ENV:Envelope>

Note the xmlns="" on elementId. Do you mean
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="http://services +.company.com/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP-ENV:Body> <ns2:getElement> <ns2:elementId>12345</ns2:elementId> </ns2:getElement> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
(note the "ns2:" prefix on elementId)?

The following steps are neccessary to achieve this result:
First, you would need to write a new serializer, which is quite easy, as it just creates the envelope and calls ->serialize_qualified() on $header and $body to fill them in. The new serializer has to declare all namespace prefixes used, the rest is just the same as the original one. Second, you'd need to overwrite the start_tag method in SOAP::WSDL::XSD::Typelib::Element to use the appropriate prefixes for the body elements.

In contrast to the original method, it would probably look up the appropriate prefix from some data set in the serializer class, so this could be the appropriate place to load SOAP::WSDL::XSD::Typelib::Element and override the method.

Something like this should do (without the handling of specialties like empty or nil elements):
%PREFIX_OF = { 'http://services.company.com/' => 'ns2' }; *SOAP::WSDL::XSD::Typelib::Element::start_tag = sub { # use prefix instead of xmlns attribute and copy the rest from # SOAP::WSDL::XSD::Typelib::Element::start_tag my $prefix = $PREFIX_OF{ $_[0]->get_xmlns() }; my $name = $_[1]->{ name } || $self->__get_name(); return "<$prefix:$name>"; }

Martin
Direct Responses: 7717 | Write a response
Posted on Tue Apr 22 04:18:25 2008 by noah in response to 7716
Re: mucking with namespaces
Nope. If I prefix all elements with 'ns2:', I get the same error as the first example in my previous email; I just need the method call prefixed. (I've been told this is a known bug in the SOAP server I'm hitting that will be fixed eventually). I wound up subclassing SOAP::WSDL::Serializer::XSD thusly:
sub serialize { my ($self, $args_of_ref) = @_; my $xml = $self->SUPER::serialize($args_of_ref); $xml =~ s#>#xmlns:ns2=\"http://services.company.com/\">#; return $xml; } sub serialize_body { my ($self, $name, $data, $opt) = @_; $data->__set_name("ns2:$name"); no warnings 'redefine'; *MyElements::getElement::get_xmlns = sub { '' }; return $self->SUPER::serialize_body($name, $data, $opt); }
If it helps, what I'm looking for is the same functionality one would get by calling...
$soap->ns('http://services.company.com/', 'ns2');
...in SOAP::Lite. My immediate problem is solved, but if there's a better way to get this done, I'm all ears. =) Thanks, Noah
Write a response