Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses

Reading an arbitrary hierarchy into a hash tree

by XPhiNermal (Initiate)
on Aug 07, 2001 at 01:49 UTC ( #102631=perlquestion: print w/replies, xml ) Need Help??
XPhiNermal has asked for the wisdom of the Perl Monks concerning the following question:

I need to read in a plain text file representing an arbitrary hierarchy of elements, where the elements are separated by newlines and the hierarchy structure is defined by tabs, like so:
foo sub1 sub2 sub21 sub22 bar camel
I would like to have my program generate the following hash tree from that text data:
my $hash_tree = { foo => { sub1 => '', sub2 => { sub21 => '', sub22 => '' } }, bar => { camel => '' } }
I have contemplated various recursive and iterative approaches to this problem, but have yet to come up with anything viable (ergo no code here).

Has anyone here done something similar before, or have a good idea of how to do it?

Thanks in advance, Bill

PS: if it makes a difference in how you would respond to such a question, I'll tell you that I'm proficient with C/C++, but am a relative beginner with Perl.

Replies are listed 'Best First'.
Re: Reading an arbitrary hierarchy into a hash tree
by abstracts (Hermit) on Aug 07, 2001 at 03:06 UTC

    Here is one way to do it. It basically uses a stack to keep pointers to the last hash created. Initially, we add a hash ref to it. For every line in our data, we count how many tabs are prepended. This tells us how deep we are in the tree and the stack should be shortened accordingly (pointers from the previous subtree are removed). This data line is then added to the hash pointed to by the last item in the stack. It is also pushed to the stack to make it the new root.

    Try tracing the code to see exactly how it works. Btw, empty hashes are used as values of leaf nodes instead of empty strings. Modifying the code to do that should not be hard.

    Hope this helps,,,


    PS. Convert the spaces in the __DATA__ to appropriate tabs.

    use Data::Dumper; my @stack; my %hash; push @stack, \%hash; while(<DATA>){ chomp; s/^(\t*)//; splice @stack, length($1)+1; push @stack, $stack[$#stack]->{$_} = {}; } print Dumper(\%hash); __DATA__ foo sub1 sub2 sub21 sub22 bar camel
    Here is the dump:
    $VAR1 = { 'foo' => { 'sub1' => {}, 'sub2' => { 'sub21' => {}, 'sub22' => {} } }, 'bar' => { 'camel' => {} } };
Re: Reading an arbitrary hierarchy into a hash tree
by runrig (Abbot) on Aug 07, 2001 at 03:30 UTC
    Just for the fun of it, here's a way which translates your text into XML, then uses XML::Simple on the result:
    use strict; use Data::Dumper; use XML::Simple; my $str = do { local $/=undef; <DATA> }; LOOP: { for ($str) { # Make start/end tags for current level s#^(\w+)(.*?)(?=^[\w<]|\Z)#<$1>$2\n</$1>\n#smg; # Process next level s/^\t//mg or last LOOP; } redo LOOP; } my $xs = XML::Simple->new(suppressempty=>''); # Add root element my $href = $xs->XMLin("<root>$str</root>"); print Dumper($href); __DATA__ abc def ghi jkl mno pqr
Re: Reading an arbitrary hierarchy into a hash tree
by maverick (Curate) on Aug 07, 2001 at 05:22 UTC
    #!/usr/bin/perl use strict; use Data::Dumper; my $struct; my $depth = -1; while(<DATA>) { my $d = $_ =~ tr/\t//; $struct .= "},\n" x ($depth-$d+1) . "$_ => {"; $depth = $d; } $struct = eval "{" . $struct . "}" x ($depth+2); print Dumper $struct; __DATA__ here is my shot at doing this Since perl is very good at string manipulation this is about the sickest way I could think to make this work out Perhaps this is not the best way but I like it


Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://102631]
Approved by root
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (9)
As of 2019-01-17 14:42 GMT
Find Nodes?
    Voting Booth?
    After Perl5, I'm mostly interested in:

    Results (307 votes). Check out past polls.