123 123 - 4 days ago 5
Linux Question

Case insensitive hash keys perl

Problem



I have a hash/array structure, some of the hash keys are not in the same case though.

I would like to know if there is a way to handle this case without manually checking the keys of every hash.

In the example below i would like all ID/iD/id/Id fields to be printed.




Example code



use warnings;
use strict;


my $Hash = {
Server => [
{
Id=>123
},
{
iD=>456
},
{
ID=>789
}
]

};

for (@{$Hash->{Server}}){
print "$_->{ID}\n"
#This is the problematic part
}





Other



perl version: v5.10.0

This data is recieved from elsewhere and must remain the same case, the example above is minimal and i cannot just simply change them all to the same case.

Any more info needed let me know.

Answer

Well, it depends a little bit on your source of information. This looks like you've parsed something, so there may be a better solution.

However, with what we've got here, I'd do it like this:

for my $entry (@{$Hash->{Server}}){
   #grep, find first match. Dupes discarded. 
   my ( $key ) = grep { /^id$/i } keys %$entry; 
   print "$key => ",$entry -> {$key},"\n";
}

This works by using grep with an i regex for case insensitive on keys, and grabbing whatever comes out first. So if you have multiple matches for /id/i then it'll be random which one you get. (sort could help with that though)

Given your working with XML though, I'd probably backtrack a bit, throw out XML::Simple and do it like this instead:

#!/usr/bin/perl
use strict;
use warnings;

use XML::Twig;

my $twig = XML::Twig -> new ( twig_handlers => { '_all_' => sub { $_ -> lc_attnames }} );
   $twig -> parse ( \*DATA );

print "XML looks like:\n";
$twig -> set_pretty_print ( 'indented_a'); 
$twig -> print;

print "Output:\n";

foreach my $server ( $twig -> get_xpath('//Server') ) { 
    print $server -> att('id'),"\n";
}

__DATA__
<XML>
   <Server ID="123" />
   <Server Id="456" />
   <Server id="789" />
</XML>

Or you can just:

foreach my $server ( $twig -> get_xpath('//Server') ) {
    $server -> lc_attnames;
    print $server -> att('id'),"\n";
}

in lieu of doing it in the twig handlers. The first answer will 'fix' all of your XML to having lower case attributes, which might not be what you want. But then, it might be useful for other scenarios, which is why I've given two examples.

Comments