Okay, a couple of things...
- I don't really understand your example
of "$page->[$id]->{'parent'}".
I don't see how that's a hash of hashes.
- I underestimated the problem, because of the "|" issue.
When I've seen this problem before, the only important
issues were:
- Nest/tab the children properly
- Do something special for hte first/last child
An example of "pipeless" output is in the method
"render_node_nopipe" below
-
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.
-
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
| [reply] [Watch: Dir/Any] [d/l] |
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 ;-) | [reply] [Watch: Dir/Any] [d/l] [select] |
i just used the stock "sort" but you could easily drop in any sort method, as long as the criteria for sorting was something htat could be looked up using the node name (or a property of hte node object if you used proper objects)
| [reply] [Watch: Dir/Any] |