2

I'm sending a fairly simple Perl hash to SOAP::Data, but I'm not getting the XML that I want with an array of hashes. Here's what I'm sending it:

'hash' => {
     'Location' => [
         {
           'key1' => 'value1',
           'key2' => 'value2',
           'key3' => 'value3',
         },
         {
           'key1' => 'value1',
           'key2' => 'value2',
           'key3' => 'value3',
         },
      ],
}

Here's what I get:

<hash>
  <Location>
      <c-gensym9>
        <key1>value1</key1>
        <key2>value2</key2>
        <key3>value3</key3>
      </c-gensym9>
      <c-gensym10>
        <key1>value1</key1>
        <key2>value2</key2>
        <key3>value3</key3>
      </c-gensym10>
  </Location>
</hash>

But what I want is this:

<hash>
    <Location>
      <key1>value1</key1>
      <key2>value2</key2>
      <key3>value3</key3>
    </Location>
    <Location>
      <key1>value1</key1>
      <key2>value2</key2>
      <key3>value3</key3>
    </Location>
</hash>

What am I missing? I suppose it'd help if I gave some code!:

my $hash = {};
my @Locations;
my @loc_codes = qw(0_4_10 0_51_117);

foreach my $l ( @loc_codes ) {
  my @arr = split ('_', $l);
  my $loc = {};
  $loc->{key1} = $arr[0];  # country
  $loc->{key2} = $arr[1];  # state
  $loc->{key3} = $arr[2];  # city

  push ( @Locations, $loc );
}

$hash->{Location} = \@Locations;  

my $soap_elements = SOAP::Data->value(
  SOAP::Data->name( 'some_method' => $hash )->prefix('p1')
)->prefix('p2');

2 Answers2

1

You need strict, first of all

use strict;
use SOAP::Lite +trace => 'all';

my @loc_codes = qw(0_4_10 0_51_117);
my @Locations;

foreach my $l ( @loc_codes ) {
  my @arr = split ('_', $l);
  my $loc =
  SOAP::Data
    ->name("Location" => \SOAP::Data->value(
      SOAP::Data->name('key1', $arr[0]),
      SOAP::Data->name('key2', $arr[1]),
      SOAP::Data->name('key3', $arr[2])));

  push ( @Locations, $loc );
}

my $soap_elements;
$soap_elements = SOAP::Data->value(
      SOAP::Data->name( hash => \@Locations ));

my $serializer = SOAP::Serializer->new();
$serializer->readable('true');
my $xml = $serializer->serialize($soap_elements);
print $xml;

generates

<hash
  soapenc:arrayType="xsd:anyType[2]"
  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:type="soapenc:Array">
 <Location>
  <key1 xsi:type="xsd:int">0</key1>
  <key2 xsi:type="xsd:int">4</key2>
  <key3 xsi:type="xsd:int">10</key3>
 </Location>
 <Location>
  <key1 xsi:type="xsd:int">0</key1>
  <key2 xsi:type="xsd:int">51</key2>
  <key3 xsi:type="xsd:int">117</key3>
 </Location>
</hash>

So I think you need to build your array elements first

KeepCalmAndCarryOn
  • 8,817
  • 2
  • 32
  • 47
0

Well ,currently , SOAP::Data is not as powerful as you imagined. It cannot dynamically or recursively analyse your compound(complex) data structure such as the nest of array , hash and scalar value.You can just pass simple data(scalar value)to SOAP::Data ,or , an SOAP::Data instance which is already assembled manually by your self thus creating a nested SOAP::Data strucure;Please refer to the SOAP::Data tutorial.

The tutorial has a simple but clear explanation on how to use SOAP::Data to deal with complex data type . But personally ,I don't recommend you to use perl as a soap client .From my previous experience, perl don't have a full support for SOAP protocal ,especially when dealing with complex data type or higher-version soap like soap 1.2.. Instead,you'd better use java .java has a very power support for latest soap and complex data type.

wuchang
  • 3,003
  • 8
  • 42
  • 66