Reputation: 142
I'm using Config::General to read from a conf file that has data in the following format:
<hash>
<array1>
val1
val2
</array1>
<array2>
val1
val2
</array2>
</hash>
While it is possible to access the array values as hash keys, it's not a particularly elegant solution.
for my $array (keys $config{'hash'}) {
for my $value (keys $config{'hash'}{$array}) {
#do stuff
}
}
Is there a way this can be changed for the data to be properly accessed as a hash of arrays, rather than resorting to this method that's somewhat of a hack? Here is the resulting structure I'm looking for:
%hash = (
array1 => [ 'value1', 'value2' ],
array2 => [ 'value1', 'value2' ]
);
Upvotes: 1
Views: 1844
Reputation: 2613
Attention!!! If you set
my $conf = new Config::General(
-ConfigFile => $config_file,
-MergeDuplicateOptions => 1
);
the solution above not work!
Upvotes: 0
Reputation: 35208
Config::General
is designed to use key value pairs. It does not provide a way to specify a list like you're trying.
One thing you can do though is supply multiple key/value pairs for the same key though, and those will be merged into an array.
use strict;
use warnings;
use Config::General;
my $conf = Config::General->new(
-String => do {local $/; <DATA>},
);
my %config = $conf->getall;
use Data::Dump;
dd \%config;
__DATA__
<hash>
array1 = val1
array1 = val2
array2 = val1
array2 = val2
</hash>
Outputs:
{
hash => { array1 => ["val1", "val2"], array2 => ["val1", "val2"] },
}
The only issue with this method is that you will have to add logic to determine if a key is an array reference or a scalar before working it. For example, the following is how you could create your own loop to go through this config:
for my $block (keys %config) {
for my $key (keys %{$config{$block}}) {
if (ref $config{$block}{$key}) {
print "$block -> $key -> @{$config{$block}{$key}}\n";
} else {
print "$block -> $key -> $config{$block}{$key}\n";
}
}
}
Outputs:
hash -> array1 -> val1 val2
hash -> array2 -> val1 val2
If you'd like a human readable config file that supports arrays, I'd recommend looking into YAML
.
The following is your config file redone in YAML format, loaded into a hash of arrays, and then outputted using Data::Dump
:
use strict;
use warnings;
use YAML;
my $conf = Load(do {local $/; <DATA>});
use Data::Dump;
dd $conf;
__DATA__
hash:
array1:
- val1
- val2
array2:
- val1
- val2
array3:
- val1
Outputs:
{
hash => {
array1 => ["val1", "val2"],
array2 => ["val1", "val2"],
array3 => ["val1"],
},
}
Upvotes: 3
Reputation: 24083
Config::General
works with key/value pairs. Your config file contains no key/value pairs, so Config::General
treats val1
and val2
as keys and assigns them a value of undef
. The resulting data structure looks like this:
{
hash => {
array1 => { val1 => undef, val2 => undef },
array2 => { val1 => undef, val2 => undef },
},
}
If your config file format is fixed, you have no choice but to hack the resulting data structure yourself. You are (ab)using Config::General
for something it wasn't intended for.
You can create arrays if you change the file format to the following:
foo.cfg
<hash>
array1 val1
array1 val2
array2 val1
array2 val2
</hash>
code
use strict;
use warnings;
use Config::General;
use Data::Dump;
my $conf = Config::General->new(
-ConfigFile => 'foo.cfg'
);
my %config = $conf->getall;
dd \%config;
Output
{
hash => { array1 => ["val1", "val2"], array2 => ["val1", "val2"] },
}
Upvotes: 3