0

I am using SOAP::Lite to use a WSDL-defined webservice.

My request (that is working fine) is like that.

<soapenv:Envelope xmlns:soapenv="http://myabc">
 <soapenv:Header/>
 <soapenv:Body>
  <foo>
     <p1>max</p1>
     <p2>frank</p2>
  </foo>
.... 

My perl code.

my $service = SOAP::Lite->service ("http://mywsdl");
my $ret = $service->foo ("max", "frank");

That is working too.

But I like to name/address my parameters p1 and p2 to have more flexibility.

I tried it with a hash

my %params = (p1 => "max", p2 => "frank");

and also with SOAP::Data.

my @params = (
 SOAP::Data->name (p1 => "max"), 
 SOAP::Data->name (p2 => "frank"));

But it is not working that way.

String value expected instead of SOAP::Data reference

Any ideas how to name my parameters?

EDIT

I like to use wsdl service. So how do I know how the service functions expect their parameters?? Thats the core of my question. I thought about the naming of parameters for a workaround.

chris01
  • 10,921
  • 9
  • 54
  • 93
  • There's a lot of information missing here. What did you do with the hash `%params`? What problem did you see using a hash? What did you do with the array `@params`? Where in the sources did your *String value expected* error arise (file and line number)? – Borodin Jan 28 '17 at 16:47
  • I agree it is not very smart to use a wsdl-service and name the paramters. But how do I know what parameters the created functions of the service have and whats the order??? – chris01 Jan 28 '17 at 19:53

3 Answers3

1

If you want to specify the names of the parameters then you should avoid creating a service, which is mostly intended to avoid such housekeeping

If you simply call the method and supply its parameters then it should do what you want

$client->call(foo =>
   SOAP::Data->name( p1 => 'max' ),
   SOAP::Data->name( p2 => 'frank' )
);

Note that

SOAP::Data->name( p1 => 'max' )

is an undocumented contraction of

SOAP::Data->name('p1')->value('max')

or

SOAP::Data->new( name => 'p1', value => 'max' )
Borodin
  • 126,100
  • 9
  • 70
  • 144
  • The part I don't understand here is how this gives more flexibility. It's a lot more code, and I think the order is still relevant. But that's the OP's claim, not yours. – simbabque Jan 28 '17 at 18:48
0

If you would like to use a WSDL file (welcome to hell), you need to use SOAP::WSDL instead of SOAP::Lite. Then you will have an utility called wsdl2perl.pl. If you run it on your wsdl file it will create a lot of perl code, including some classes for each service defined in the wsdl file.

Then in your code you instantiate a new instance of the specific endpoint you want to use, and then you call on this object methods named after the services offered on this endpoint (you do not use the call method anymore), passing a hash reference with all parameters.

You will still need to know what parameters are expected because there is not a lot of introspection available (you can have a workaround that because if you pass an unknown parameter name to the classes they will die and in the error message you will have the list of available parameters, so you can catch that and parse the error string. Ugly, but I did not find another way to do it).

Patrick Mevzek
  • 10,995
  • 16
  • 38
  • 54
  • SOAP::WSDL is integrated in SOAP::Lite and should not be used any more. wsdl2perl is not required for SOPA::Lite wsdl-service. So whats the miracle to know what parameters the service-function do have and in what order??? – chris01 Jan 28 '17 at 20:22
  • 1
    You have `stubmaker.pl` in `SOAP::Lite`. Maybe browsing the code it produces can give hints on how to access parameters. It seems each service class has a `parameters` method giving back a list of `SOAP::Data` objects with name and type. – Patrick Mevzek Jan 29 '17 at 18:42
  • Maybe: `SOAP::Schema->new(parse => $file)->services()->{$service}->{'parameters'}` – Patrick Mevzek Jan 29 '17 at 18:44
  • See also [this previous answer](http://stackoverflow.com/a/3144948/6368697) – Patrick Mevzek Jan 30 '17 at 22:04
-1

I don't think you can name the parameters if you create the stubs from the service descriptions by calling service().

If you want to assign values to the parameters, there is an example available on CPAN.

Function sayHello

 <sayHello xmlns="urn:HelloWorld">
   <name xsi:type="xsd:string">Kutter</name>
   <givenName xsi:type="xsd:string">Martin</givenName>
 </sayHello>

SOAP request

 use SOAP::Lite;
 my $soap = SOAP::Lite->new( proxy => 'http://localhost:81/soap-wsdl-test/helloworld.pl');
 $soap->default_ns('urn:HelloWorld');
 my $som = $soap->call('sayHello',
    SOAP::Data->name('name')->value('Kutter'),
    SOAP::Data->name('givenName')->value('Martin')
 );
 die $som->faultstring if ($som->fault);
 print $som->result, "\n";

You have to replace the value of proxy to http://mywsdl, name and givenName to p1 and p2, sayHello to foo and urn:HelloWorld to your WSDLs namespace.

I also recommend to check this. All the requests can be done without SOAP::Lite.

Community
  • 1
  • 1
user3606329
  • 2,405
  • 1
  • 16
  • 28
  • *"All the requests can be done without `SOAP::Lite`"* That may be so, but isn't very much help. It's an [*If I were you, I wouldn’t start from here*](https://simonkidd.wordpress.com/2010/08/12/if-i-were-you-i-wouldnt-start-from-here/) answer and it involves hand-coding a significant amount of XML, which is what the `SOAP` modules are designed to avoid. – Borodin Jan 28 '17 at 17:01
  • @ Borodin: I'm afraid but you are wrong. Building a huge nested call with SOAP::Lite takes much longer than parsing the WSDL one time with a SOAP client (for example Boomerang) and writing it in heredoc style. Furthermore, it seems you have not understood that my answer is based on SOAP::Lite and the refered link is more or less only an idea. – user3606329 Jan 28 '17 at 17:30
  • This isn't a *huge nested call*. And are you talking about coding time, execution time, network time? I think coding time is hugely reduced by using `SOAP::SQLite` (unless you count references to Stack Overflow). I also understand that your final sentence was notional, but do you think I must not comment on it, or that it can't be improved? – Borodin Jan 28 '17 at 18:17
  • I would also point out that the voting on Stack Overflow is anonymous by design. Even if you *think* you know who placed the vote, the intention is that you should behave as if you have no idea. Tit-for-tat voting is unconstructive at the best of times, and is always a contravention of the rules. – Borodin Jan 28 '17 at 18:26
  • @simbabque: It all looks intact to me. Please explain! And I don't like to think of it as a rant, but perhaps it's for others to judge. – Borodin Jan 28 '17 at 18:51
  • _I downvote posts that I think are useful overall, regardless of any mistakes_. The rant was meant with a wink. :-) – simbabque Jan 28 '17 at 18:57
  • @Borodin: There is no need to rewrite an official example from the documentation. I also don't care much about votes here as I barely vote myself. Your comments are all based on guesses and appear to be too aggressive for a normal discussion. – user3606329 Jan 28 '17 at 20:58
  • @simbabque: Gah! And I can't even contort that sentence into something that I meant to say! Thank you for your help. – Borodin Jan 28 '17 at 21:12
  • @user3606329: *"There is no need to rewrite an official example from the documentation"* I agree completely. So don't do it. If you want to alert the OP that his question is already answered in the documentation then you should provide a hyperlink. If you have no other insight into the situation then you should post that link in a comment, or not at all. – Borodin Jan 28 '17 at 21:21
  • 1
    @user3606329: *"Your comments are all based on guesses"*. No. They are based on my understanding of the Perl language and of Stack Overflow. *"And appear to be too aggressive for a normal discussion"* I apologise if you feel that way. My intention is always to be inclusive and liberal. – Borodin Jan 28 '17 at 21:25