Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

Can a hash key have a scalar value and also contain a hash?

by bcarroll (Pilgrim)
on Jun 23, 2014 at 22:20 UTC ( [id://1090976]=perlquestion: print w/replies, xml ) Need Help??

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

Not sure how to properly word this question, or if it has already been asked using better wording...

I am parsing a file that is similar to a Windows registry file and building a hash from the key structure in the file.
The issue I am running into is the way the file is structured (pretty much identical to the Windows registry). I would like the resulting hash to mimic the file content structure, but I don't think it is possible to assign a value to a key that has subkeys under it (hash of hashes), in this case isn't the hash of the subkeys the value?

The only way I could think of that works is to create an array under the key (if it has a scalar value and subkeys) and make the "default value" the first element then any subkeys would become hashes in the other elements.

Not sure if their is a CPAN module that can tackle this task or if it is just not possible.

Here is a sample of the contents of the registry-ish file I am parsing (file.reg):

HKEY_LOCAL_MACHINE\SOFTWARE\VENDOR\PRODUCT\CurrentVersion\Reports\Name +spaceProviders=25137 ODBC:= reportsodbclog; REG_SZ SQLBulkInsertFlushInterval= 0x3c; REG_DWORD SQLBulkInsertFlushRowCount= 0x3e8; REG_DWORD SYSLOG:= reportssyslog; REG_SZ TEXT:= reportstextlog; REG_SZ HKEY_LOCAL_MACHINE\SOFTWARE\VENDOR\PRODUCT\CurrentVersion\SessionServe +r=12060 MaintenancePeriod= 0x3c; REG_DWORD MaintenanceQueryTimeout= 0x3c; REG_DWORD HKEY_LOCAL_MACHINE\SOFTWARE\VENDOR\PRODUCT\CurrentVersion\SessionServe +r\NamespaceProviders=32225 LDAP:= ssprovider_ldap; REG_SZ ODBC:= ssprovider_db; REG_SZ

#Currently I am creating a key named 'DEF_VAL' and assigning the paren +t key's value to that. Any suggestions? use warnings; use strict; use Data::Dumper; print Dumper loadreg('file.reg'); sub loadreg{ my $registry; open(REGISTRY,'<',shift) or die("Error loading registry: $!\n"); my @reg = <REGISTRY>; close REGISTRY; my $head = 0; my $section = ""; for my $line ( @reg ) { #if ( $line =~ /^\s?(HKEY.*)\n/ ) { if ( $line =~ /^\s?HKEY.*?CurrentVersion\\(.*)\n/ ) { # found start of section $head = 1; my ( $key , $def_val ) = split /=/ , $1; $key =~ s/\\/\//g; $registry->{$key}{"DEF_VAL"} = $def_val; $section = $key; } elsif ( $head == 1 and $line =~ /^\n$/ ) { $head = 0; $section = ""; } elsif ( $head == 1 and $line =~ /^[a-z]/i ) { # this is a key/value line for the current section # MaxReferralHops= 0xa; REG_DWORD # LDAP:= dsldap; REG_SZ $line =~ /^([^=:]+)[:=]+\s+([^;]+);\s+([^ ]+)\n$/; my $value = $2; $value = hex($value) if $value =~ /^0x/; $registry->{$section}{$1}{"VALUE"} = $value if $1; $registry->{$section}{$1}{"TYPE"} = $3 if $1; } } return($registry); }
Here is the output from the above example:
$VAR1 = { 'SessionServer/NamespaceProviders' => { 'ODBC' => { 'VALUE' +=> 'ssprovider_db', 'TYPE' = +> 'REG_SZ' }, 'LDAP' => { 'VALUE' +=> 'ssprovider_ldap', 'TYPE' = +> 'REG_SZ' }, 'DEF_VAL' => '32225' }, 'SessionServer' => { 'DEF_VAL' => '12060' }, 'Reports/NamespaceProviders' => { 'TEXT' => { 'VALUE' => 're +portstextlog', 'TYPE' => 'REG +_SZ' }, 'ODBC' => { 'VALUE' => 're +portsodbclog', 'TYPE' => 'REG +_SZ' }, 'SYSLOG' => { 'VALUE' => ' +reportssyslog', 'TYPE' => 'R +EG_SZ' }, 'DEF_VAL' => '25137' } };

Replies are listed 'Best First'.
Re: Can a hash key have a scalar value and also contain a hash?
by SuicideJunkie (Vicar) on Jun 23, 2014 at 22:39 UTC

    Note: Regkey and Regvalue used to maintain a distinction from the hash definition of the terms key and value.

    Perhaps you want an extra step, and to have a hash of regkeys=>{...} and regvalues=>{...}. You can't have two regkeys with the same name or two regvalues with the same name, but you can have a regkey and a regvalue with the same name.

    { 'Regkeys' => { HKEY_CURRENT_USER => { 'Regkeys'=>{...}, 'Regvalues'=>{'(default)'=>{type=>REG_SZ, value=>un +def}, ...}, }, HKEY_LOCAL_MACHINE => {...}, }, 'Regvalues' => {'(default)'=>{type=>REG_SZ,value=>undef}, ...}, }
Re: Can a hash key have a scalar value and also contain a hash?
by AppleFritter (Vicar) on Jun 23, 2014 at 22:46 UTC

    "but I don't think it is possible to assign a value to a key that has subkeys under it (hash of hashes), in this case isn't the hash of the subkeys the value?"

    Indeed. Each key/value pair in a hash maps precisely one key to precisely one value; so it can't be both a scalar and a hash reference at the same time, though you're of course right that you could use an array there as an extra layer of indirection.

    Searching CPAN immediately reveals Win32::Registry::File, and the much newer Parse::Win32Registry. Have you looked at those?

      I did look at some of the Win32 registry modules, but I can't recall why I ended up not using them.

      I am thinking it was because, although the file structure is similar to a Windows registry file, it is different enough to make it incompatible with the available modules, and more complicated than just writing my own parsing subroutine.

      Or I may have just been overwhelmed by the module's source code and got too intimidated to try... I honestly can't remember.

Re: Can a hash key have a scalar value and also contain a hash?
by 2teez (Vicar) on Jun 23, 2014 at 22:36 UTC

    Hi bcarroll,

    I must confess I didn't get what you wanted done properly, but am sure what you are trying to do is not Impossible if properly expressed with a likely show of how the expected output is suppose to look like.
    That been said, while you want to show that, you can also look at this documentation perldsc.

    If you tell me, I'll forget.
    If you show me, I'll remember.
    if you involve me, I'll understand.
    --- Author unknown to me
      Here is an example of the result I was dreaming of (given the example data):
      my $registry = loadreg('file.reg'); print $registry->{'SessionServer/NamespaceProviders'}; # would print 3 +2225 print $registry->{'SessionServer/NamespaceProviders'}{'ODBC'}; # would + print ssprovider_db print $registry->{'SessionServer/NamespaceProviders'}{'ODBC'}{'TYPE'}; + # would print REG_SZ

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1090976]
Approved by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (5)
As of 2024-04-19 07:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found