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

Re: [soaplite] force an array on deserialization

Expand Messages
  • Andrew Dolbey
    Your suggestion works very well for me. Thanks, Duncan! There s a little busy work I ll have to do to put back in a single hash which datastruct elements go
    Message 1 of 3 , Jun 25, 2004
    • 0 Attachment
      Your suggestion works very well for me.  Thanks, Duncan!  There's a little busy work I'll have to do to put back in a single hash which datastruct elements go with which QueryBundle elements (an unpredictable many-to-one mapping), but this is probably easy enough to do.

      I'm replying here to all, as what I learned might be helpful for others.  Where I went wrong was to call $som->valueof( ) on an element that was too high up in the structure, at a top struct level.  This is where a hash was being created, where keys must be unique, of course, and so will clobber existing values with the same key as the message body is being processed.  So, this will come up short:

         my $data = $som->valueof('//QueryData')

      as it'll be a hash with only one key, and only one of the `datastruct' pieces as its value;  a version like what you showed me, on the other hand:

         my @dataStructs = $som->valueof('//datastruct')

      grabs all of the `datastruct' pieces for me.

      Thanks again for your help with this.


      Duncan Cameron wrote:
      At 2004-06-25, 08:38:13 you wrote:
      Hi all,
      I'm working on a tool where a Perl SOAP::Lite client has to 
      communicate with a Lisp-based SOAP server.  The Lisp service is 
      sending back to me a sequence of structs.  SOAP::Lite can handle SOAP 
      *arrays* from Lisp with no problems, but the Lisp API doesn't like 
      sending arrays of structs, and so sends *sequences* of structs 
      instead.  Sequences of structs in Lisp are essentially lists of 
      lists, but when Perl receives them, it interprets them as a bunch of 
      identically named hashes.  This causes problems.  
      The actual message structure looks like this:
        <QueryBundle> -struct
          <QueryInfo>   -struct
             <inputVal>  - one string
             <inputKind> - one string
          <QueryData> - array of 1+ structs (problem is here!)
            <datastruct> - struct
               <resultVal> - one string
               <resultType> - one string
      Lisp is sending back a sequence of `datastruct' elements in the 
      `QueryData' piece.  SOAP::Lite deserializes this sequence as a hash, 
      and so all we have left at the end is the final `datastruct' element 
      processed.  If SOAP::Lite were to deserialize the `QueryData' piece 
      as an array full of anonymous hashes, then I think the problem would 
      go away.  But they're not anonymous.  Rather, they're named, all with 
      the same name.  The name has the status of default XML tags 
      like '<item>' in cases like this:
      where the tag is there more to delimit values than to provide a 
      meaningful label.
      On a trace, I can see that all the `datastruct' instances are sitting 
      in the soap message body, just waiting to be plucked out.  But I 
      don't know how I can make calls to access them.  I tried making a 
      Perl QueryData class, and using that as a type identifier for the 
      message data, but I don't know how to specify the one-or-more-
      elements array nature of the the QueryData piece.  I also tried a 
      few calls to $som->values, $som->dataof, and the like, but didn't 
      have any success with them either.
      Does this code do what you want to achieve?
      use strict;
      use SOAP::Lite;
      my $xml = <<'END';
              <resultVal>result val 1</resultVal>
              <resultType>result type 1</resultType>
              <resultVal>result val 2</resultVal>
              <resultType>result type 2</resultType>
              <resultVal>result val 3</resultVal>
              <resultType>result type 3</resultType>
      my $s = SOAP::Deserializer->new;
      my $som = $s->deserialize($xml); # som is normally returned by your SOAP call
      for my $i ($som->valueof('//datastruct')) {
          print map({qq|$_ => "$i->{$_}" |} keys %{$i}), "\n";
    Your message has been successfully submitted and would be delivered to recipients shortly.