Loading ...
Sorry, an error occurred while loading the content.

Re: [soaplite] Accessing multiple return values of the same complex type

Expand Messages
  • Paul Kulchenko
    Hi, Dave! First two (long) quotes that explain the situation. Then solution ... That s both simple and tricky question. Say you have something like:
    Message 1 of 2 , Aug 7, 2001
    • 0 Attachment
      Hi, Dave!

      First two (long) quotes that explain the situation. Then solution

      ----------------------------------------------------------------

      That's both simple and tricky question. Say you have something like:
      <data>
      <item>12</item>
      <item>13</item>
      </data>

      If you try to deserialize it and get the value, you'll get hash with
      one (!) key 'item' and value 13. Why? because <data> element will be
      deserialized as hash and since hash can have only unique keys, they
      will be collapsed in one. There is no Perl data structure that can
      handle it, but to be able to deal with it, you can navigate thru
      envelope with SOM methods. For example:

      $som = SOAP::Deserialized->deserialize(....);
      --OR--
      $som =
      $s->uri($muri)->proxy('http://localhost/sapsoap')->autotype(0)->readable(1)->$meth(@parms);

      foreach ($som->valueof('//item')) {
      print "$_\n";
      }

      will print both 12 and 13 in this case.

      So, SOAP::Lite will try to deserialize to Perl structures for as as
      much as possible, but if it doesn't work for some reason (as above)
      you can always navigate thru it with SOAP::SOM methods.

      You may also consider to provide your own deserializer (take a look
      into examples/XML/customxml.pl) or provide deserializer only for
      specific type.

      Btw, if you deserialize 'data' as an ARRAY, then ALL elements will be
      visible and accessible. Hope it helps.

      ----------------------------------------------------------------

      There are three different types:

      array (marked with arrayType, all subelements has the same name,
      represented as an array in Perl)

      <something arrayType="">
      <item>1</item>
      <item>2</item>
      </something>

      struct (all subelements have different names, represented as a hash
      in Perl)

      <something>
      <item1>1</item1>
      <item2>2</item2>
      </something>

      something else (subelements MAY have the same name. There is no
      construction to represent it in Perl)

      <something>
      <item1>1</item1>
      <item1>2</item1>
      </something>

      You may want to represent it as hash, I may want something else.
      That's why SOAP::Lite gives you several choices.
      (1) You may iterate thru it with methods of SOAP::SOM object. Not
      very convenient.
      (2) You may write your own deserializer and navigate with your
      methods (like in examples/XML/customxml.pl). Not always applicable,
      mostly useful on client side.
      (3) You may provide deserializer for specific type (Vector) in your
      case and represent your data as YOU want.

      add this method into SOAP::Deserializer or inherit your deserializer
      from SOAP::Deserializer and register it on client/server side with
      ->deserializer(My::Deserializer->new) call.

      sub as_Vector {
      my $self = shift;
      [ map { scalar(($self->decode_object($_))[1]) } @{$_[3] || []} ];
      }

      change it to 'sub SOAP::Deserializer::as_Vector' if you want to add
      it to SOAP::Deserializer.

      Any method with name as_SOMETHING will be called on deserializing
      type SOMETHING (case sensitive), which will return array in your
      case.

      ----------------------------------------------------------------

      Solution:

      use SOAP::Lite service =>

      'http://services.xmltoday.com/vx_engine/wsdl_publish.vep/realtime.wsdl';

      my $symbb = "MSFT+IBM+ADBE";
      my @parameters = (
      SOAP::Data->name(stockticker => {symbol => "$symbb"})
      );

      my $quotes = getRTQuote(@parameters); # returned value is not used
      my $response = SOAP::Lite->self->call; # we'll access envelope
      directly

      foreach ($response->valueof('//stock_quote')) {
      my $inlinet = "Info for $_->{'symbol'}:" .
      "...Last Sale: " . $_->{'last'} . "\n";
      print $inlinet;
      }

      Best wishes, Paul.

      --- "Bleicher, Dave" <dbleicher@...> wrote:
      > Howdy,
      >
      > I'm trying to learn how to use SOAP for sending and receiving
      > complex data
      > types. I've written the code below to use the multiple symbol
      > realtime
      > quote service at XMLToday.com (see WSDL in code). I've gotten
      > almost
      > everything to work and then hit a brick wall.
      >
      > The service request and response are both complex types. In short,
      > you send
      > a list of ticker symbols (wrapped in a complex structure) and the
      > service
      > responds with multiple complex structures (one for each symbol in
      > your list)
      > containing various data. This works fine, with one exception: I
      > can only
      > get data for the last symbol in the list.
      >
      > By running SOAP::Lite with +trace, I've verified that the service
      > is
      > responding with multiple fragments (one for each symbol in $symbb)
      > each of
      > which is named "stock_quote". It looks like each one overwrites
      > the
      > previous one in my result set. I had expected (silly me) to be
      > able to loop
      > over the returned hash reference (in $quotes) to get each one. I
      > was wrong.
      > Dumping $quotes (Data::Dump) shows a blessed object containing only
      > the data
      > for the last symbol.
      >
      > I tried to use the paramsout method from the docs, but couldn't get
      > it to
      > solve the problem. I should mention that I'm fairly new to both
      > SOAP and
      > Perl. The former has been a great deal easier thanks to
      > SOAP::Lite.
      > Excellent work Paul!
      >
      > The (almost) working code is below. Any thoughts?
      >
      > Thanks,
      > David
      > ---
      > --
      > -
      >
      > ## Code only prints data for last symbol (ADBE)
      > ## can't figure out how to get data for other symbols
      > ## returned by call.
      > ##
      > use SOAP::Lite service =>
      >
      'http://services.xmltoday.com/vx_engine/wsdl_publish.vep/realtime.wsdl';
      > my $symbb = "MSFT+IBM+ADBE";
      > my @parameters = (
      > SOAP::Data->name(stockticker => {symbol => "$symbb"})
      > );
      > my $quotes = getRTQuote(@parameters);
      > my $inlinet = "Info for $quotes->{stock_quote}->{'symbol'}:" .
      > "...Last Sale: " . $quotes->{stock_quote}->{'last'};
      >
      > print $inlinet;
      >
      > ------------------------ Yahoo! Groups Sponsor
      >
      > To unsubscribe from this group, send an email to:
      > soaplite-unsubscribe@yahoogroups.com
      >
      >
      >
      > Your use of Yahoo! Groups is subject to
      > http://docs.yahoo.com/info/terms/
      >
      >


      __________________________________________________
      Do You Yahoo!?
      Make international calls for as low as $.04/minute with Yahoo! Messenger
      http://phonecard.yahoo.com/
    Your message has been successfully submitted and would be delivered to recipients shortly.