Hello Monastery Dwellers,

I am a new Perl convert, still trying to master the basics of the language. Coming from Python, the concept of object references has been giving me a bit of trouble and as such, I've come to ask for some clarification.

I've started out by reading an XML file using XML::Simple, but have been urged to move into XML::LibXML.

My goal is to iterate through the loaded hash and remove key/value pairs from each hash within the array where key names are listed in a pre-defined array.

This is a sample of the XML that I'm loading

<?xml version='1.0' encoding='UTF-8' standalone='yes' ?> <smses count="4110"> <sms protocol="0" address="1234567890" date="1288032888762" type="1" + subject="null" body="Hey, I'm out of class." toa="null" sc_toa="null +" service_center="null" read="1" status="-1" locked="0" /> <sms protocol="0" address="0987654321" date="1288032888762" type="1" + subject="null" body="What are you up to this afternoon?" toa="null" +sc_toa="null" service_center="null" read="1" status="-1" locked="0" / +> </smses>

The array (via Dumper) looks like:

#$VAR1 = { # 'count' => '5509', # 'sms' => [ # { # 'protocol' => '0', # 'locked' => '0', # 'status' => '0', # 'date' => '1288194026703', # 'subject' => 'null', # 'toa' => 'null', # 'sc_toa' => 'null', # 'body' => 'You should come to dinner with us! :) +', # 'read' => '1', # 'address' => '(123) 456-7890', # 'type' => '2', # 'service_center' => 'null' # }, # { # 'protocol' => '0', # 'locked' => '0', # 'status' => '64', # 'date' => '1288224316833', # 'subject' => 'null', # 'toa' => 'null', # 'sc_toa' => 'null', # 'body' => 'INVADER ZIM!!', # 'read' => '1', # 'address' => '0987654321', # 'type' => '2', # 'service_center' => 'null' # },
Ignoring the actual values of the keys, the above XML loads into a hashref that looks like above Dumper'd output. What I'm trying to do is iterate through all of the Hash's in the sms array. Within each hash, all I'm trying to do is delete key pairs where the key nam does NOT reside in a pre-defined list (@keysToKeep).

#! /usr/bin/env perl use XML::Simple; use Data::Dumper; use strict; use warnings; ######## ########### Variables ######## # List of info we want for each message entry my @keysToKeep = ('date', 'body', 'addr +ess', 'type'); # XML Parser my $xml = new XML::Simple; ######## ########### Subroutines ######## # Filepath is passed to load a hashref # a CLEANED Hashref is returned of the xml we've loaded sub loadFileToHashRef { my $xmlRef = $xml->XMLin($_[0]); # Clean our hash for my $textRef ( @{$xmlRef->{sms}} ) { foreach my $key (keys %{$textRef}) { # If your $key is *not* what we're looking for +, remove it from the hash if ( !grep ($key, @keysToKeep) ) { delete $textRef->{$key}; } } } # Return our hash ref return $xmlRef; } my $hashRef = loadFileToHashRef("xml/sms-20110704030000.xml"); print Dumper $hashRef;
Now, this code doesn't remove elements from the hash and I know why. Using keys only returns a list of the pairs that I'm modifying. I'm not actually modifying the hashref. My question becomes this: How do I modify the hashref (%hashRef) directly?

Given that the above doesn't do what I'm trying to do, I started working with 'each'. Here's what I came up with.

#! /usr/bin/env perl use XML::Simple; use Data::Dumper; use strict; use warnings; use 5.012; ######## ########### Variables ######## # List of info we want for each message entry my @keysToKeep = ('date', 'body', 'addr +ess', 'type'); # XML Parser my $xml = new XML::Simple; ######## ########### Subroutines ######## # Filepath is passed to load a hashref # a CLEANED Hashref is returned of the xml we've loaded sub loadFileToHashRef { my $xmlRef = $xml->XMLin($_[0]); while (($key, $value) = each %{$xmlRef}) { print "Key: $key, Value: $value \n"; } # Return our hash ref return $xmlRef; } my $hashRef = loadFileToHashRef("xml/sms-20110704030000.xml"); print Dumper $hashRef;

However, I continually get the following, and I don't understand why.

Global symbol "$key" requires explicit package name at ./parse.pl line + 29. Global symbol "$value" requires explicit package name at ./parse.pl li +ne 29. Global symbol "$key" requires explicit package name at ./parse.pl line + 31. Global symbol "$value" requires explicit package name at ./parse.pl li +ne 31. Execution of ./parse.pl aborted due to compilation errors.

I also now know that this won't do what I'm trying to do either as the each function doesn't allow for element removal from the hash.

I highly suspect that my PHP and Python ideologies are getting in the way of my understanding of how Perl handles Hashes and Arrays (as it pertains to references). Ideally, I'm looking for the following feedback

-- Libra


In reply to Parsing an Array of Hashes, Modifying Key/Value Pairs by librarat

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.