marcjb has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to set the body of a SOAP request to a given string (the data may come from a file, for example), but I am getting an extra tag that is causing my call to error at the server. Basically, I want Soap Lite (or another library) to let me fill in EXACTLY what goes between <soap:Body> and </soap:Body> Here is the test code:
#!/usr/bin/perl use SOAP::Lite +trace; my ($server, $endpoint, $soapaction, $method, $body, $envelope); $server = 'http://127.0.0.1'; $endpoint = "$server/Just_Some_Test"; $soapaction = "Just_Some_Test"; # This will eventually come from a file $body = qq~<wsap:GetData soapenv:encodingStyle="http://schemas.xmlsoap +.org/soap/encoding/"> <Just_A_String> </Just_A_String> </wsap:GetData> ~; # Set the envelope - Will eventually contain other specific stuff my $envelope = SOAP::Serializer->new(); $envelope-> register_ns ("http://www.w3.org/2001/XMLSchema-instance", +"xsi"); $envelope-> register_ns ("http://www.w3.org/2001/XMLSchema", "xsd"); # Initialize the object my $getData = SOAP::Lite -> serializer ($envelope) -> uri ($soapaction) -> readable (1) -> proxy ($endpoint) -> on_fault(sub { my($soap, $res) = @_; die ref $res ? "ERROR " . $res->faultdetail : "ERROR +" .$soap->transport->status, "\n"; }) ; # Make the call and set the Body of the message my $response = $getData->call( method => SOAP::Data->type(xml => $body +) ); if ( $response->fault ) { printf "***A fault (%s) occurred: %s\n", $response->faultcode, $response->faultstring; } else { print "***Response: " . $response->result . "\n"; } exit;
The above code produces the following:
<?xml version="1.0" encoding="UTF-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <method xmlns="Just_Some_Test"> <wsap:GetData soapenv:encodingStyle="http://schemas.xmlsoap.org/ +soap/encoding/"> <Just_A_String> </Just_A_String> </wsap:GetData> </method> </soap:Body> </soap:Envelope>
I've looked at some of the threads on setting the body to raw XML, but there always seems to be some extra tags left over. The above is almost perfect! I just need to get rid of:
<method xmlns="Just_Some_Test">
and it's closing tag. Can this be done?

Replies are listed 'Best First'.
Re: SOAP? Setting BODY Manually
by Anonymous Monk on Jul 17, 2008 at 03:49 UTC
    Rewrite call to do what you want
    sub call { SOAP::Trace::trace('()'); my $self = shift; die "A service address has not been specified either by using SOAP +::Lite->proxy() or a service description)\n" unless defined $self->proxy && UNIVERSAL::isa($self->proxy => +'SOAP::Client'); $self->init_context(); my $serializer = $self->serializer; $serializer->on_nonserialized($self->on_nonserialized); my $response = $self->transport->send_receive( context => $self, # this is provided for context endpoint => $self->endpoint, action => scalar($self->on_action->($serializer->uriformetho +d($_[0]))), # leave only parameters so we can later update them if + required envelope => $serializer->envelope(method => shift, @_), encoding => $serializer->encoding, parts => @{$self->packager->parts} ? $self->packager->parts + : undef, ); return $response if $self->outputxml; my $result = eval { $self->deserializer->deserialize($response) } if $response; if (!$self->transport->is_success || # transport fault $@ || # not deserializible # fault message even if transport OK # or no transport error (for example, fo TCP, POP3, IO impleme +ntations) UNIVERSAL::isa($result => 'SOAP::SOM') && $result->fault) { return ($self->on_fault->($self, $@ ? $@ . ($response || '') : $result) || $result ); # ? # trick editors } # this might be trouble for connection close... return unless $response; # nothing to do for one-ways # little bit tricky part that binds in/out parameters if (UNIVERSAL::isa($result => 'SOAP::SOM') && ($result->paramsout || $result->headers) && $serializer->signature) { my $num = 0; my %signatures = map {$_ => $num++} @{$serializer->signature}; for ($result->dataof(SOAP::SOM::paramsout), $result->dataof(SO +AP::SOM::headers)) { my $signature = join $;, $_->name, $_->type || ''; if (exists $signatures{$signature}) { my $param = $signatures{$signature}; my($value) = $_->value; # take first value # fillup parameters UNIVERSAL::isa($_[$param] => 'SOAP::Data') ? $_[$param]->SOAP::Data::value($value) : UNIVERSAL::isa($_[$param] => 'ARRAY') ? (@{$_[$param]} = @$value) : UNIVERSAL::isa($_[$param] => 'HASH') ? (%{$_[$param]} = %$value) : UNIVERSAL::isa($_[$param] => 'SCALAR') ? (${$_[$param]} = $$value) : ($_[$param] = $value) } } } return $result; } # end of call()
    On second thought, it looks as though you should create a custom serializer
      Sorry for the delay in responding (I've been out for a few days). Thank you very much for taking the time to respond. I may be able to define the name of the function and have that removed from the file, so I can then get away without a custom serializer. Otherwise, I have some work ahead of me! Thanks again, Marc