ecuguru has asked for the wisdom of the Perl Monks concerning the following question:

Hail XML Gurus..
When I try to poll Yahoo and parse the response, I'm getting an error I've never seen and don't understand:
Pseudo-hashes are deprecated at WebYahooSites2.pl line 28. Argument "\x{42}\x{72}..." isn't numeric in hash element at WebYahooSi +tes2.pl line 28. Bad index while coercing array into hash at WebYahooSites2.pl line 28.
This is my entire perl source code. Anyone see anything obvious that I'm doing wrong? I've noticed that when I set the number of responses (xml responses) to 1, the code works. It's when there are multiple entries that it freaks out with this error.
#!/usr/bin/perl -w use strict; use LWP::UserAgent; my $ua = LWP::UserAgent->new; $ua->timeout(10); $ua->env_proxy; my $resp; ##Holds the content my $appID = "YahooDemo"; my $resultsNum = "5"; my $site = 'http://api.search.yahoo.com/WebSearchService/V1/webSearch? appid=YahooDemo&query=Spears&results='.$resultsNum.'&format=html'; my $response = $ua->get($site); if ($response->is_success) { $resp = $response->content; # or whatever } else { my $err = $response->status_line; print "Error: $err \n"; } use XML::Simple; my $xml = new XML::Simple; my $doc = $xml->XMLin($resp); my $recordNum = 0; for( ref $doc->{Result} eq "HASH"?$doc->{Result}:ref $doc->{Result}eq +"ARRAY"?@{$doc- >{Result}}:() ){ print "Title: $doc->{Result}{Title}\n"; print "Url: $doc->{Result}{Url}\n"; print "MimeType: $doc->{Result}{MimeType}\n"; print "Cache URL: $doc->{Result}{Cache}{Url}\n"; $recordNum++; } exit;

Replies are listed 'Best First'.
Re: Parsing Yahoo XML Response
by GrandFather (Saint) on Jan 06, 2007 at 09:20 UTC

    As the error message states there is a problem in line 28, but that is one nasty bit of obfusicated code! Lets break it up a little:

    my @list; if (ref $doc->{Result} eq "HASH") { @list = $doc->{Result}; } elsif (ref $doc->{Result} eq "ARRAY") { @list = @{$doc->{Result}}; } else { @list = (); } for( @list ){

    Layed out like that it looks like a lot of work! The guts is that it is supposed to generate a list and iterate over it. The complication is that the list may be generated from an array ref or a hash ref. Note though that the sigil used in the first assignment is for a scalar, yet we know there is actually a reference to a hash, and the lhs expects to see a list. Something isn't right! Changing the line to:

    @list = keys %{$doc->{Result}};

    may be what is required. Assuming that fixes the problem, you can re-obfusicate the code by using nested terniary operators, squeezing white space and munging the lot onto one line as a trap for the next maintainer. :)


    DWIM is Perl's answer to Gödel
      This seems to be working. Does it look better to you?
      Thanks
      my $yahoo_response = get($req_url); my $xmlsimple = XML::Simple->new(); my $yahoo_xml = $xmlsimple->XMLin($yahoo_response); foreach my $result (@{$yahoo_xml->{Result}}) { # Make sure result has a thumbnail my $title = $result->{Title}; my $url = $result->{Url}; my $click_url = $result->{ClickUrl}; # $click_url =~ s/&/&amp;/g; if (ref($result->{Cache}) eq "HASH") { ##If it has a Cache at all my $cacheUrl = $result->{Cache}->{Url}; my $cacheSize = $result->{Cache}->{Size}; $out .= "Record: $count<br>\n"; $out .= "Title: $title<br>\n"; $out .= "Url: $url<br>\n"; $out .= "CacheUrl: $cacheUrl<br>\n"; $out .= "CacheSize: $cacheSize<br>\n"; } print "out\n$out----\n"; $out = ""; $count++; }
      thank you for the answer, but I wasn't able to understand all of your suggestions, despite what seems like a very well written set of suggestions. Believe me it's my ignorance to this.
      Did you mean that I should change the for loop to:
      for( ref $doc->{Result} eq "HASH"?keys %{$doc->{Result}}:ref $doc->{Re +sult}eq "ARRAY"?@{$doc->{Result}}:() ){
      ?? If so, I still get the same error. Is there another way to run the loop? Thanks!

        In that case I suggest that you try the "expanded" version of the line - that will be much easier to diagnose. If you still have trouble try generating a code sample that demonstrates the problem without requiring the extranious code. Something like this:

        #!/usr/bin/perl -w use strict; my $doc = {Result => {first => 1, second => 2} #['first', 'second'] }; my @list; if (ref $doc->{Result} eq "HASH") { @list = keys %{$doc->{Result}}; } elsif (ref $doc->{Result} eq "ARRAY") { @list = @{$doc->{Result}}; } else { @list = (); } for (@list) { print "$_\n"; }

        which prints the following (without errors or warnings):

        first second

        You might also like to use Data::Dump::Streamer to dump the contents of $doc so that you can see what is causing grief in the data.


        DWIM is Perl's answer to Gödel
Re: Parsing Yahoo XML Response
by merlyn (Sage) on Jan 06, 2007 at 11:17 UTC
      Nah, I liked the Yahoo::Search CPAN module and it made the first pass at this cake, but it wouldn't let me access Mime Type. My problem is that I want to access all documents that are html AND text, but it seems like you can only choose one or the other in the type declaration.

      So I was writing something that would let me select all, and then manually check each result to make sure it was an html or txt type. If the module has a means of being able to do this, I'm all ears. But trying to access MimeType just comes back with an error that it can't find that property in the lib.
      Thanks!
Re: Parsing Yahoo XML Response
by Anonymous Monk on Jan 06, 2007 at 09:08 UTC