0

Trying to extract information from a XML file using this piece of snippet, I'm not getting the desired output as intended and I know its something within the foreach loop, -> My question how one can use the foreach loop in this case

 use strict;
 use XML::Simple;
 use Data::Dumper;

 my %top_in_ou_bi;
 $top_in_ou_bi{"input"}{name}=add;
 $top_in_ou_bi{"input"}{name}=clk;
 $top_in_ou_bi{"input"}{name}=dat_in;
 $top_in_ou_bi{"output"}{name}=dat_out;
 $top_in_ou_bi{"bidirection"}{name}=ctrl;

 foreach my $nam(sort keys %top_in_ou_bi){
        foreach my $dat(keys %{$top_in_ou_bi{$nam}}){
                print"$nam $dat: $top_in_ou_bi{$nam}{$dat}\n";
   }
 }

output:

bidirection name: ctrl
input name: dat_in
output name: dat_out

Expected output:

bidirection name: ctrl
input name: dat_in
input name: clk
input name: add
output name: dat_out

also using "use strict" warns that barewords are not allowed, how one can surpass this warning!

Thanks!

EDIT

I'd like to know if the below snippet is a valid one?

   my $top_in=$root_top->{input};
   my $top_ou=$root_top->{output};
   my $top_bi=$root_top->{bidirection};
   foreach my $name(keys %$top_in)
   {
     print "input $name\n";
    }
   foreach my $name(keys %$top_ou)
   {
     print "output $top_ou->{name}\n";
   }
   foreach my $name(keys %$top_bi)
   {
     print "bidirection $top_bi->{name}\n";
   }
Divox
  • 101
  • 6
  • 1
    I think the barewords warning is because you assign "add" to a variable without quotes or anything. "add" isn't a keyword. This applies to all following vars too. – Arc676 Dec 17 '15 at 07:31

2 Answers2

7

It has nothing to do with the foreach loop. The problem is how you are populating your %top_in_ou_bi hash. A hash can only contain a single value for each key. When you store multiple values under the key "input", only the last one remains.

The best you can do here is store an array (by reference) at each key rather than a scalar value. Or you can use a module like Hash::MultiValue.

To suppress the barewords warning, don't use barewords. Quote things ('add' instead of add, etc.) or declare variables (depending on what you're trying to accomplish).

Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
  • I still am little confused, can you please give an example by storing it in an array(by reference). unfortunately Hash::Multivalue module is not installed, requires admin permission @Ted Hopp – Divox Dec 17 '15 at 07:43
  • 1
    @GRD - Take a look at [this answer](http://stackoverflow.com/a/17571954/535871). You can also do a web search for _perl hash of arrays_ to get lots of other code examples. – Ted Hopp Dec 17 '15 at 07:56
  • 1
    @GRD, administrator permission is not required to use a module. You can install it in a local folder you control, rather than the main module folder. However, I would not use a module for this. An array reference is the standard, easy solution to this problem (the module was designed to solve a problem related to a specific use case, which doesn't apply to your code). –  Dec 17 '15 at 09:33
  • @TedHopp Is there any way just without using an array reference we can solve this, because I just tried it and I did get the output.The worst case scenario: Let's imagine that there can be multiple number of "input", "output" or "bidirection"(shown in the snippet) , using an array reference would become tedious IMO!. Any way around using "foreach" loops! – Divox Dec 17 '15 at 10:27
  • @dan1111 thank you! I tried it, but I have another question directed to TedHopp. Any solution that can solve ? thanks – Divox Dec 17 '15 at 10:29
  • 1
    @GRD - I assume that since you marked this solved that you figured things out. In my opinion, there's no better alternative than to store an array reference at each hash key. Populating the hash is not tedious because of Perl's [autovivification](http://perlmaven.com/autovivification) behavior, requiring only a minor change of syntax when storing values. And treating every stored value as an array ref means simply adding another loop level when you want to process those values. It's all pretty clean, once you get used to it. – Ted Hopp Dec 17 '15 at 16:59
  • @TedHopp yes I figured a different approach and i'm just comparing them right now! thank you for that info :) – Divox Dec 18 '15 at 04:07
1

If you think about the pattern of your data you will understand that either input, output or bidirectional may contain a list of group of properties. You also mentioned that

there can be multiple number of "input", "output" or "bidirection"

In a comment of Ted Hopp's answer. It means you have such data which is a list by nature and to store such data the best structure is array. A very basic point of data structure. Ted Hopp has pointed out the original problem correctly. However, if you are unsure to write the proper code, following snippet might be helpful

use strict;
use XML::Simple;
use Data::Dumper;

my %top_in_ou_bi = ('input' => [], 'output' => [], 'bidirectional' => []);
push @{$top_in_ou_bi{'input'}}, {name => 'add', 'new' => 'value'};
push @{$top_in_ou_bi{'input'}}, {name => 'clk'};
push @{$top_in_ou_bi{'input'}}, {name => 'dat_in'};
push @{$top_in_ou_bi{'output'}}, {name => 'dat_out'};
push @{$top_in_ou_bi{'bidirection'}}, {name => 'ctrl', 'something' => 'else'};

foreach my $type(sort keys %top_in_ou_bi){
    foreach my $properties (@{$top_in_ou_bi{$type}}){
        foreach my $key (keys %$properties){
            print "$type $key: $$properties{$key}\n";
        }
    }
}

OUTPUT:

bidirection name: ctrl
bidirection something: else
input name: add
input new: value
input name: clk
input name: dat_in
output name: dat_out
Samiron
  • 5,169
  • 2
  • 28
  • 55
  • I have attached another edit in the snippet, any thoughts on that snippet! @Samiron – Divox Dec 17 '15 at 11:16
  • 1
    Looking at `keys %$top_in` in your snippet. `$top_in` itself a hash here. Hence the problem still remained the same. If you want to change only the printing part of my answer, you need to use like `@$top_in`. – Samiron Dec 17 '15 at 11:30