Dirk80 has asked for the wisdom of the Perl Monks concerning the following question:

Hello,

I've written a script to print the Process Tree. To be able to print it nicely I decided to use Data::TreeDumper.

Here you can see the code:

#!/usr/bin/perl use strict; use warnings; use Data::Dumper; use Tree::Simple; use Tree::Simple::View::HTML; use Data::TreeDumper; use Win32::Process::Info; use 5.010; use feature qw(say); ############################################################ # Get Subprocesses ############################################################ my $pi = Win32::Process::Info->new(); my %sub_pids = $pi->Subprocesses(); remove_win32_subprocess_recursion(\%sub_pids); add_win32_subprocess_root_entry(\%sub_pids); # e.g. 'ROOT' => [204,5944,3824,0] sub add_win32_subprocess_root_entry { my( $ref_subs ) = @_; my @total_sub_pid_list; for my $ref_sub_pid_list (values %$ref_subs) { for my $sub_pid (@$ref_sub_pid_list) { push(@total_sub_pid_list, $sub_pid); } } my @root_pid_list; for my $pid (keys %$ref_subs) { unless( $pid ~~ @total_sub_pid_list ) { push(@root_pid_list, $pid); } } $ref_subs->{'ROOT'} = [@root_pid_list]; } # remove win32 subprocess recursions # e.g. '0' => [0,4] # --> '0' => [4] sub remove_win32_subprocess_recursion { my( $ref_subs ) = @_; while( my ($pid, $ref_sub_pid_list) = each %$ref_subs ) { if( $pid ~~ $ref_sub_pid_list ) { @$ref_sub_pid_list = grep(!/$pid/, @$ref_sub_pid_list); } } } ############################################################ # Create Process Tree ############################################################ my $root_pid = 'ROOT'; my $pid_tree = Tree::Simple->new($root_pid, Tree::Simple->ROOT); build_pid_tree($root_pid, $pid_tree); $pid_tree->DESTROY(); sub build_pid_tree { my ($pid, $pid_tree) = @_; if( scalar @{ $sub_pids{$pid} } == 0 ) { return; } for my $item ( @{ $sub_pids{$pid} } ) { build_pid_tree( $item, Tree::Simple->new($item, $pid_tree) ); } } ############################################################ # TRAVERSE TREE ############################################################ print "Relevant Information:\n"; $pid_tree->traverse( \&print_tree ); print "\n"; sub print_tree { my ($tree) = @_; print (("\t" x $tree->getDepth()), $tree->getNodeValue(), "\n"); } ############################################################ # View Tree (Data::TreeDumper) ############################################################ print "Unfiltered Tree:Simple tree:\n"; print DumpTree($pid_tree, 'Win32 Process Tree'); print "\n"; print "Filtered Tree::Simple tree:\n"; print DumpTree($pid_tree, 'Win32 Process Tree', FILTER => sub { my $s = shift; if('Tree::Simple' eq ref $s) { # TODO } return(Data::TreeDumper::DefaultNodesToDisplay($s)) ; });

The script is detecting all running processes. Then all PIDs are put into a tree (by using Tree::Simple).

To show you what I want to have I traversed the tree and printed it.

Now I want to do the same printing with Data::TreeDumper. But I am not getting it. I do not really understand the filters. I read the help, but I don't get it.

The input is a Tree::Simple process tree. But this tree has of course a lot of more information in which I am NOT interested. You can see this tree by looking at the output directly behind print "Unfiltered Tree:Simple tree:\n";.

After the print "Filtered Tree::Simple tree:\n"; I try to only print the content of the nodes. But I do not understand the filter.

I know that the return value of the filter is consisting of three parts. A node type, an eventual new structure and a list of 'keys' to display.

For example I tried the following to only get the nodes:

print DumpTree($pid_tree, 'Win32 Process Tree', FILTER => sub { my $s = shift; if('Tree::Simple' eq ref $s) { return( 'SCALAR', undef, $_{'node'} ); } return(Data::TreeDumper::DefaultNodesToDisplay($s)) ; });

But I get a weird result and some warnings:

Filtered Tree::Simple tree: Win32 Process Tree blessed in 'Tree::Simple' `- = undef [S1]

I also tried it with an array instead of the scalar. But I also get weird results.

Thanks for your help.

Greetings,

Dirk

Replies are listed 'Best First'.
Re: Help to understand the Data::TreeDumper Filters
by Eliya (Vicar) on Apr 12, 2011 at 17:19 UTC
    return( 'SCALAR', undef, $_{'node'} );

    I have no experience with Data::TreeDumper filters, but this $_{'node'} looks very strange.  What is this meant to be?

    Also, the docs say "The filter returns the node's type, an eventual new structure (see below) and a list of 'keys' to display. The keys are hash keys or array indexes.".  In other words, as long as you return "keys-to-display", it doesn't seem to make sense to have 'SCALAR' as type (as you can apply neither keys nor indices).

    I wonder if

    return( 'HASH', undef, 'node' );

    would be closer to what you want... (presuming 'node' is the key you want to display)

      Sorry for my long post. I now summarized my real problem in a small example.

      #!/usr/bin/perl use strict; use warnings; use Data::TreeDumper; my $s = {'name' => 'Homer', 'surname' => 'Simpson', 'kids' => [ { 'name' => 'Bart', 'surname' => 'Simpson' }, { 'name' => 'Lisa', 'surname' => 'Simpson' }, { 'name' => 'Maggie', 'surname' => 'Simpson' }], 'wife' => { 'name' => 'Marge', 'surname' => 'Simpson' }}; my $OnlyName = sub { my $s = shift ; if('HASH' eq ref $s) { # TODO return('HASH', undef, grep { /^name$/} keys %$s) ; } return(Data::TreeDumper::DefaultNodesToDisplay($s)) ; }; print DumpTree($s, 'The Simpsons', DISPLAY_ADDRESS => 0, FILTER => $OnlyName) ; ############################################################ # UNFILTERED OUTPUT ############################################################ #The Simpsons #|- kids #| |- 0 #| | |- name = Bart #| | `- surname = Simpson #| |- 1 #| | |- name = Lisa #| | `- surname = Simpson #| `- 2 #| |- name = Maggie #| `- surname = Simpson #|- name = Homer #|- surname = Simpson #`- wife # |- name = Marge # `- surname = Simpson ############################################################ # FILTERED OUTPUT (only name) ############################################################ #The Simpsons #|- kids #| |- 0 #| | |- name = Bart #| |- 1 #| | |- name = Lisa #| `- 2 #| |- name = Maggie #|- name = Homer #`- wife # |- name = Marge

      I have a hash. I want to print it with Data::TreeDumper. My goal is it to only print the keys of the hash which are called "name". (see FILTERED OUTPUT (only name)).

      How do I have to write the filter? My suggestion was

      return('HASH', undef, grep { /^name$/} keys %$s) ;
      but this is NOT working.

      Thank you for your help.

        but this is NOT working.

        It's always a good idea to mention how exactly it doesn't work — that way you enhance your chances of getting a useful reply, because not everyone is willing to install non-standard modules (+ dependencies) just to figure out what you could have mentioned right away. And often, an educated guess can be made without having the module installed, as long you have all relevant info available.  But thanks for following up with self-contained sample code.

        That said, I did install the module to confirm my suspicion that the not-working output is

        The Simpsons `- name = Homer

        Reason is that if you only let 'name' pass through the filter, DumpTree won't recurse into the other entries 'kids' and 'wife'... In other words, in this particular case, you could do:

        return('HASH', undef, grep { !/^surname$/} keys %$s) ;

        Output:

        The Simpsons |- wife | `- name = Marge |- name = Homer `- kids |- 0 | `- name = Bart |- 1 | `- name = Lisa `- 2 `- name = Maggie