Joel G Mathew
Joel G Mathew

Reputation: 8061

Error using keys on a hash

I have the following code:

my $xmlrpc = XML::RPC->new('http://api.opensubtitles.org/xml-rpc');
my $result = $xmlrpc->call('SearchSubtitles', $token, @args);    

&lp ("Number of subtitle files found:".keys $result->{data});
my $count=0;
mkdir "./Subs";
foreach my $key ( keys $result->{data} )
{

The compilation fails with the error:

Type of argument to keys on reference must be unblessed hashref or arrayref at /root/subtitlegetter/getsubs.pl line 210.

on both lines containing the keys statement.

$result looks like this:

$result  = {
          'seconds' => '0.014',
          'status' => '200 OK',
          'data' => [
                      {
                        'SubFeatured' => '0',
                        'SubHearingImpaired' => '0',
                        'SubAuthorComment' => undef,
                        'SubDownloadLink' => 'http://dl.opensubtitles.org/en/download/filead/src-api/vrf-cc714a2b91/1951829762.gz',
                        'MovieNameEng' => undef,
                        'SubDownloadsCnt' => '2225',
                        'MovieName' => '"24" Day 4: 7:00 a.m.-8:00 a.m.',
                        'LanguageName' => 'English',
                        'MovieFPS' => '25.000',
                        'SeriesIMDBParent' => '285331',
                        'MovieHash' => '9dfc670867516a39',
                        'SeriesEpisode' => '1',
                        'UserNickName' => 'dvkempen',
                        'MovieYear' => '2005',
                        'SubSize' => '41095',
                        'MovieKind' => 'episode',
                        'IDSubMovieFile' => '125384',
                        'ZipDownloadLink' => 'http://dl.opensubtitles.org/en/download/subad/src-api/vrf-b48cd22d58/3253187',
                        'SubBad' => '0',
                        'ISO639' => 'en',
                        'IDSubtitle' => '3253187',
                        'MovieReleaseName' => '24.S04E01.WS.DVDRip.XviD-MEDiEVAL',
                        'MatchedBy' => 'moviehash',
                        'MovieTimeMS' => '2474000',
                        'UserID' => '1019339',
                        'SubFormat' => 'srt',
                        'MovieByteSize' => '366661632',
                        'SubRating' => '0.0',
                        'SubComments' => '0',
                        'SubActualCD' => '1',
                        'SubHash' => 'ab8ad6d19af1579361929b3f71d61b60',
                        'UserRank' => 'silver member',
                        'IDSubtitleFile' => '1951829762',
                        'SubSumCD' => '1',
                        'SubFileName' => '24.S04E01.WS.DVDRip.XviD-MEDiEVAL.srt',
                        'SubAddDate' => '2008-02-24 20:44:01',
                        'IDMovieImdb' => '502251',
                        'SubtitlesLink' => 'http://www.opensubtitles.org/en/subtitles/3253187/24-day-4-7-00-a-m-8-00-a-m-en',
                        'IDMovie' => '73012',
                        'SeriesSeason' => '4',
                        'SubHD' => '0',
                        'SubLanguageID' => 'eng',
                        'MovieImdbRating' => '8.5'
                      },
                      {
                        'SubFeatured' => '0',
                        'SubHearingImpaired' => '0',
                        'SubAuthorComment' => undef,
                        'SubDownloadLink' => 'http://dl.opensubtitles.org/en/download/filead/src-api/vrf-d165613c14/1951854096.gz',
                        'MovieNameEng' => undef,
                        'SubDownloadsCnt' => '4521',
                        'MovieName' => '"24" Day 4: 7:00 a.m.-8:00 a.m.',
                        'LanguageName' => 'English',
                        'MovieFPS' => '25.000',
                        'SeriesIMDBParent' => '285331',
                        'MovieHash' => '9dfc670867516a39',
                        'SeriesEpisode' => '1',
                        'UserNickName' => 'mephistogrigo',
                        'MovieYear' => '2005',
                        'SubSize' => '40794',
                        'MovieKind' => 'episode',
                        'IDSubMovieFile' => '144086',
                        'ZipDownloadLink' => 'http://dl.opensubtitles.org/en/download/subad/src-api/vrf-18f9de1a19/4380524',
                        'SubBad' => '0',
                        'ISO639' => 'en',
                        'IDSubtitle' => '4380524',
                        'MovieReleaseName' => '24.Season.4.DVDRip.XviD-MEDiEVAL',
                        'MatchedBy' => 'moviehash',
                        'MovieTimeMS' => '2474000',
                        'UserID' => '446711',
                        'SubFormat' => 'srt',
                        'MovieByteSize' => '366661632',
                        'SubRating' => '0.0',
                        'SubComments' => '0',
                        'SubActualCD' => '1',
                        'SubHash' => '4d9d67b580efe4b6378d3cb34b4d2a75',
                        'UserRank' => 'gold member',
                        'IDSubtitleFile' => '1951854096',
                        'SubSumCD' => '1',
                        'SubFileName' => '24.4x01.Day.4.07am-08am.DVDRip.XviD.iNTERNAL-MEDiEVAL.EN.srt',
                        'SubAddDate' => '2008-04-13 14:23:34',
                        'IDMovieImdb' => '502251',
                        'SubtitlesLink' => 'http://www.opensubtitles.org/en/subtitles/4380524/24-day-4-7-00-a-m-8-00-a-m-en',
                        'IDMovie' => '73012',
                        'SeriesSeason' => '4',
                        'SubHD' => '0',
                        'SubLanguageID' => 'eng',
                        'MovieImdbRating' => '8.5'
                      },
                      {
                        'SubFeatured' => '0',
                        'SubHearingImpaired' => '0',
                        'SubAuthorComment' => undef,
                        'SubDownloadLink' => 'http://dl.opensubtitles.org/en/download/filead/src-api/vrf-d383210797/138228.gz',
                        'MovieNameEng' => undef,
                        'SubDownloadsCnt' => '582',
                        'MovieName' => '"24" Day 4: 7:00 a.m.-8:00 a.m.',
                        'LanguageName' => 'English',
                        'MovieFPS' => '25.000',
                        'SeriesIMDBParent' => '285331',
                        'MovieHash' => '9dfc670867516a39',
                        'SeriesEpisode' => '1',
                        'UserNickName' => 'wr975 (a)',
                        'MovieYear' => '2005',
                        'SubSize' => '41175',
                        'MovieKind' => 'episode',
                        'IDSubMovieFile' => '2004768',
                        'ZipDownloadLink' => 'http://dl.opensubtitles.org/en/download/subad/src-api/vrf-b7f71cab8b/4292367',
                        'SubBad' => '0',
                        'ISO639' => 'en',
                        'IDSubtitle' => '4292367',
                        'MovieReleaseName' => '24 - Season 4 - E01-08',
                        'MatchedBy' => 'moviehash',
                        'MovieTimeMS' => '0',
                        'UserID' => '48281',
                        'SubFormat' => 'srt',
                        'MovieByteSize' => '366661632',
                        'SubRating' => '0.0',
                        'SubComments' => '0',
                        'SubActualCD' => '1',
                        'SubHash' => 'b6c8e5422afbb6d748040c5d401445e3',
                        'UserRank' => 'bronze member',
                        'IDSubtitleFile' => '138228',
                        'SubSumCD' => '1',
                        'SubFileName' => '24.401-med.srt',
                        'SubAddDate' => '2005-08-23 00:00:00',
                        'IDMovieImdb' => '502251',
                        'SubtitlesLink' => 'http://www.opensubtitles.org/en/subtitles/4292367/24-day-4-7-00-a-m-8-00-a-m-en',
                        'IDMovie' => '73012',
                        'SeriesSeason' => '4',
                        'SubHD' => '0',
                        'SubLanguageID' => 'eng',
                        'MovieImdbRating' => '8.5'
                      },
                      {
                        'SubFeatured' => '0',
                        'SubHearingImpaired' => '0',
                        'SubAuthorComment' => undef,
                        'SubDownloadLink' => 'http://dl.opensubtitles.org/en/download/filead/src-api/vrf-d596b9fa4f/1952794930.gz',
                        'MovieNameEng' => undef,
                        'SubDownloadsCnt' => '772',
                        'MovieName' => '"24" Day 4: 7:00 a.m.-8:00 a.m.',
                        'LanguageName' => 'English',
                        'MovieFPS' => '25.000',
                        'SeriesIMDBParent' => '285331',
                        'MovieHash' => '9dfc670867516a39',
                        'SeriesEpisode' => '1',
                        'UserNickName' => undef,
                        'MovieYear' => '2005',
                        'SubSize' => '41307',
                        'MovieKind' => 'episode',
                        'IDSubMovieFile' => '2587404',
                        'ZipDownloadLink' => 'http://dl.opensubtitles.org/en/download/subad/src-api/vrf-627cac3bd1/4119493',
                        'SubBad' => '0',
                        'ISO639' => 'en',
                        'IDSubtitle' => '4119493',
                        'MovieReleaseName' => 'S04E01 iNTERNAL WS DVDRip XviD MEDiEVAL',
                        'MatchedBy' => 'moviehash',
                        'MovieTimeMS' => '0',
                        'UserID' => '0',
                        'SubFormat' => 'srt',
                        'MovieByteSize' => '366661632',
                        'SubRating' => '0.0',
                        'SubComments' => '0',
                        'SubActualCD' => '1',
                        'SubHash' => '295dfd2ab8ded0c6d14ed6555796f9d0',
                        'UserRank' => undef,
                        'IDSubtitleFile' => '1952794930',
                        'SubSumCD' => '1',
                        'SubFileName' => '24.S04E01.iNTERNAL.WS.DVDRip.XviD-MEDiEVAL_(ENGLISH)_DJJ.HOME.SAPO.PT.srt',
                        'SubAddDate' => '2011-03-01 22:37:54',
                        'IDMovieImdb' => '502251',
                        'SubtitlesLink' => 'http://www.opensubtitles.org/en/subtitles/4119493/24-day-4-7-00-a-m-8-00-a-m-en',
                        'IDMovie' => '73012',
                        'SeriesSeason' => '4',
                        'SubHD' => '0',
                        'SubLanguageID' => 'eng',
                        'MovieImdbRating' => '8.5'
                      }
                    ]
        };

I find it hard to wrap my head around keys, coming from a programming language that had nothing like hashes. Could you kindly let me know what's wrong with the code?

I should probably mention that though I've used strict and warnings, the same code compiles fine on Activestate perl 5.16.3 running in Windows, while it fails in perl 5.14.2 running on Debian.

Edit: I've updated the content of $result according to data from Dumper.

Upvotes: 1

Views: 5068

Answers (2)

Miller
Miller

Reputation: 35198

I would advise you to not use keys on a scalar or an array. Perl the perldoc (emphasis mine):

Starting with Perl 5.14, keys can take a scalar EXPR, which must contain a reference to an unblessed hash or array. The argument will be dereferenced automatically. This aspect of keys is considered highly experimental. The exact behaviour may change in a future version of Perl.

   for (keys $hashref) { ... }
   for (keys $obj->get_arrayref) { ... }

Instead, just use it on a hash, like so:

foreach my $key ( keys %{$result->{data}[0]} ) {

Upvotes: 1

Slade
Slade

Reputation: 1364

The keys function expects a valid hash (or array, in 5.12 or later) as its argument. In 5.14 an experimental feature was introduced where several such array/hash functions (including keys, push, and others) will implicitly attempt to dereference a scalar expression, which would allow you to do something like this:

my $hash_ref = { foo => 1 };
print keys $hash_ref;

Rather than explicitly dereferencing:

my $hash_ref = { foo => 1 };
print keys %{ $hash_ref };

However this feature is considered highly experimental* and is likely to be removed in future versions. A valid use of it (such as the example above) will produce a warning:

keys on reference is experimental at ... line ...

And an invalid use will produce the error you're getting:

my $foo = "This is not a hash ref";
print keys $foo;

Type of argument to keys on reference must be unblessed hashref or arrayref at -e line 1.

*Experimental has an official meaning in regards to Perl features. Any feature flagged as experimental is prone to removal and/or backwards-compatibility-breaking changes without further warning.

The solution to your problem is to simply not use keys on a scalar expression. This means you need to dereference your data structure accesses appropriately so the argument to keys is an array or hash variable. If I'm not misinterpreting the way you wrote your structure, the syntax would be something like:

foreach my $key (keys %{ $result->{data} }) { ... }

Upvotes: 6

Related Questions