Roboz has asked for the wisdom of the Perl Monks concerning the following question:
I've been having some good success coding a SOAP::Lite client to retrieve and parse a complicated XML document from an Apache web service, especially due to great help I've found reading this web site. Now I'm stuck on a problem and need to finally ask a question of the Perl Monks:
The following code, XML data and Dumper output has been simplified to concentrate on the issue at hand. The data doesn't make much sense but I have maintained the complexity of what I'm working with. I have no control over the XML schema.
OK, when I run this code it usually does what I need it to do, which is retrieve an XML document, parse the document for specific data and output it as text.
#!/usr/bin/perl # use SOAP::Lite; use Data::Dumper; # Load server CA certificate # $ENV{HTTPS_CA_FILE} = "ca.cer"; my $soap = SOAP::Lite->new(proxy => 'https://webserver:443/ToyService/ +ToyWebService'); $soap->readable(1); # Setup credentials # sub SOAP::Transport::HTTP::Client::get_basic_credentials { return 'user' => 'pass'; # Execute SOAP Request # sub doSOAPCall { my $method = $_[0]; eval { my $res = $soap->call($method)->result; return $res; 1; } or die; } # Build method and parameters for GetToys and execute call to web serv +ice # my $getFrobMethod = SOAP::Data->name('getToys') ->attr({xmlns => 'web.service.namespace'}); my $getToysResults = &doSOAPCall($getToysMethod); # Print output for TOYS # foreach my $e (@{$getToysResults->{Toys}{Toy}}){ print "$e->{color}\n"; if ($e->{ToyLocations}{ToyLocation}{locationName}){ $location = $e->{ToyLocations}{ToyLocation}{locationName}; $location = "XXX$location"; } else { $location = "XXX"; } print "TOYS\/$e->{color}\/$e->{ToyLocations}{ToyLocation}{toyName} +\/$e->{ToyLocations}{ToyLocation}{toyQuantity}\/$location\/\n"; }
The problem hits when there is an additional array of data within the XML. This gives the following error:
Not a HASH reference at ... line ...
This would specifically be at the if statement when there's more than one "ToyLocation".
Here's the resulting XML data from SOAP::Lite debug:
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xm +lns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenc="ht +tp://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org +/2001/XMLSchema"> <env:Header/> <env:Body> <m:getResponse xmlns:m="web.service.namespace"> <ns1:result xmlns:n1="web.service.namespace"> <ns2:Toys xmlns:ns2="web.service.namespace.value" xsi: +type="ns2:ArrayOfToy"> <ns2:Toy xsi:type="ns2:Stuffed"> <ns2:ToyLocations xsi:type="ns2:ArrayOfToyLoca +tion"> <ns2:ToyLocation> <ns2:toyName>bear</ns2:toyName> <ns2:toyQuantity>2</ns2:toyQuantity> <ns2:locationName>toybox</ns2:location +Name> </ns2:ToyLocation> </ns2:ToyLocations> <ns2:color>brown</ns2:color> <ns2:size>large</ns2:size> </ns2:Toy> <ns2:Toy xsi:type="ns2:Electric"> <ns2:ToyLocations xsi:type="ns2:ArrayOfToyLoca +tion"> <ns2:ToyLocation> <ns2:toyName>car</ns2:toyName> <ns2:toyQuantity>2</ns2:toyQuantity> <ns2:locationName>shelf</ns2:locationN +ame> </ns2:ToyLocation> </ns2:ToyLocations> <ns2:color>red</ns2:color> <ns2:size>small</ns2:size> </ns2:Toy> <ns2:Toy xsi:type="ns2:Board"> <ns2:ToyLocations xsi:type="ns2:ArrayOfToyLoca +tion"> <ns2:ToyLocation> <ns2:toyName>Sorry</ns2:toyName> <ns2:toyQuantity>1</ns2:toyQuantity> <ns2:locationName>toybox</ns2:location +Name> </ns2:ToyLocation> <ns2:ToyLocation> <ns2:toyName>Chess</ns2:toyName> <ns2:toyQuantity>4</ns2:toyQuantity> <ns2:locationName>shelf</ns2:locationN +ame> </ns2:ToyLocation> </ns2:ToyLocations> <ns2:color>none</ns2:color> <ns2:size>medium</ns2:size> </ns2:Toy> </ns2:Toys> </ns1:result> </m:getResponse> </env:Body> </env:Envelope>
and here's the Dumper results:
$VAR1 = { 'Toys' => bless( { 'Toy' => [ bless( { 'ToyLoc +ations' => bless( { + 'ToyLocation' => { + 'toyName' => 'bear', + 'toyQuantity' => '2', + 'locationName' => 'toybo +x' + } + }, 'ArrayOfToyLocation' ), 'color' + => 'brown', 'size' +=> 'large' }, 'Stuff +ed' ), bless( { 'ToyLoc +ations' => bless( { + 'ToyLocation' => { + 'toyName' => 'car', + 'toyQuantity' => '2', + 'locationName' => 'shelf +' + } + }, 'ArrayOfToyLocation' ), 'color' + => 'red', 'size' +=> 'small' }, 'Elect +ric' ), bless( { 'ToyLoc +ations' => bless( { + 'ToyLocation' => [ + { + 'toyName' => ' +Sorry', + 'toyQuantity' +=> '1', + 'locationName' + => 'toybox' + }, + { + 'toyName' => ' +Chess', + 'toyQuantity' +=> '4', + 'locationName' + => 'shelf' + } + ] + }, 'ArrayOfToyLocation' ), 'color' + => 'none', 'size' +=> 'medium' }, 'Board +' ) ] }, 'ArrayOfToy' ) };
I've tried a nested foreach to go through the locations like so:
foreach my $e (@{$getToysResults->{Toys}{Toy}}){ foreach my $f (@{$e->{ToyLocations}{ToyLocation}}){ ...
and get a "Can't use undefined value as a HASH reference at..." error. I've also tried using 'valueof' and 'dataof' and XPath as noted in the SOAP::SOM docs and get a "Can't call method "dataof" on unblessed reference at ..." error.
Any help is appreciated!
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Problem parsing SOAP::SOM result of SOAP::Lite client Query - Not a HASH reference
by McA (Priest) on Sep 27, 2012 at 12:27 UTC | |
by Anonymous Monk on Sep 27, 2012 at 13:14 UTC |