in reply to representing a tree graphically...

While you solved your problem, and it (apparently) works -- assuming that someone will some day have to maintain/modify this, it will be a nightmare.

I would suggest that you parse 'treepaths' into a true tree datastructure of some kind (either nested Objects, or a simple hash of hashes). Once you have that, rendering tree's in the way you describe becomes extremely trivial using a recursive method which takes a "node" and a "indenting" depth as input.

Replies are listed 'Best First'.
(cLive ;-) Re: representing a tree graphically...
by cLive ;-) (Prior) on Jan 09, 2002 at 04:00 UTC
    They already are in a HoH structure
    $page->[$id]->{'parent'} = whatever..
    The 'treepath' element is just there to make sorting them a lot easier.

    Since it's 'trivial' to render, perhaps you could provide an example? That would really help! Oh, and although I didn't specifiy, the graphical representation is for a web page.

    thanks

    cLive ;-)

      Okay, a couple of things...

      1. I don't really understand your example of "$page->[$id]->{'parent'}". I don't see how that's a hash of hashes.

      2. I underestimated the problem, because of the "|" issue. When I've seen this problem before, the only important issues were:
        1. Nest/tab the children properly
        2. Do something special for hte first/last child
        An example of "pipeless" output is in the method "render_node_nopipe" below

      3. Even with the pipes, I still think it's cleaner to use a recursive method -- BUT, instead of passing an "indent" depth, you pass an acctuall padding string, that contains the pipes. The only real new complexity is that when dealing with each node, it's not enough to know if that node is the last of it's siblings, you also have to know if it's parent was the last of it's siblings (in order to build up the padding string properly).
        An example of the recursive solution is the method "render_node" below.

      4. It should be clear how to make this generate the appropriate HTML (<img src..>) output by modifing the single letter vars.

      #!/usr/local/bin/perl -w use strict; my $d = " #"; my $t = " +"; my $l = " \\"; my $p = " |"; my $s = " "; my $tree = { 'one' => { 'two' => { 'five' => { 'boo' => { 'baz' => { }, }, }, }, 'three' => { 'four' => { }, 'yak' => { }, 'six' => { 'foo' => { 'yuk' => { }, }, 'ggg' => { }, }, }, }, }; print "with pipes...\n" . &render_node($tree->{'one'}, 'one'); print "no pipes...\n" . &render_node_tab($tree->{'one'}, 'one'); sub render_node { my ($tree, $node, $tok, $pad, $last) = @_; $tok = $s unless defined $tok; $pad = "" unless defined $pad; $last = 1 unless defined $last; my $out = $pad . $tok . $d . $node . "\n"; my @kids = sort keys %{$tree}; for (my $i = 0; $i < scalar @kids; $i++) { my $knode = $kids[$i]; my $ktree = $tree->{$knode}; my $klast = ($i+1 == scalar @kids); my $ktok = ($klast ? $l : $t); my $kpad = $pad . ($last ? $s : $p); $out .= &render_node($ktree, $knode, $ktok, $kpad, $klast); } return $out; } sub render_node_tab { my ($tree, $node, $tok, $indent) = @_; $tok = $s unless defined $tok; $indent = 0 unless defined $indent; my $out = ($s x $indent) . $tok . $d . $node . "\n"; my @kids = sort keys %{$tree}; for (my $i = 0; $i < scalar @kids; $i++) { my $knode = $kids[$i]; my $ktree = $tree->{$knode}; my $ktok = ($i+1 == scalar @kids) ? $l : $t; my $kindent = $indent+1; $out .= &render_node_tab($ktree, $knode, $ktok, $kindent); } return $out; } __END__ with pipes... #one + #three | + #four | + #six | | + #foo | | | \ #yuk | | \ #ggg | \ #yak \ #two \ #five \ #boo \ #baz no pipes... #one + #three + #four + #six + #foo \ #yuk \ #ggg \ #yak \ #two \ #five \ #boo \ #baz
        Re 1: Hash starts off as $page->{$id}-{'parent'}, but for readability's sake I created a second, ordered array of hashes that was the original IDs mapped to an array index showing the correct display order (ie, sorted by 'treepath'). It was just easier to visualise.

        Nice code, but one thing's not as it should be (which I implied, but didn't specify *explicitly* before). I need the nodes to display in order (to allow users to build the order they want pages displayed in when menus are drawn, so they need to be sorted by 'treepath', eg:

        #one + #two | \ #five | \ #boo | \ #baz \ #three + #four + #yak \ #six + #foo | \ #yuk \ #ggg
        and not the re-ordered way that your code outputs the tree at the moment, if that makes sense.

        But thanks for the insight. I'll have a little play with the ideas you presented.

        cLive ;-)