NAME

Data::TreeDumper - dumps a data structure in a tree fashion.

SYNOPSIS

  use Data::TreeDumper ;
  
  my $sub = sub {} ;
  
  my $s = 
  {
  A => 
  	{
  	a => 
  		{
  		}
  	, bbbbbb => $sub
  	, c123 => $sub
  	, d => \$sub
  	}
  	
  , C =>
	{
  	b =>
  		{
  		a => 
  			{
  			a => 
  				{
  				}
  				
  			, b => sub
  				{
  				}
  			, c => 42
  			}
  			
  		}
  	}
  , ARRAY => [qw(elment_1 element_2 element_3)]
  } ;
    
  
  #-------------------------------------------------------------------
  # package setup data
  #-------------------------------------------------------------------
  
  $Data::TreeDumper::Useascii = 0 ;
  $Data::TreeDumper::Maxdepth = 2 ;
  $Data::TreeDumper::Filter   = \&Data::TreeDumper::HashKeysSorter ;
  
  print Data::TreeDumper::DumpTree($s, 'title') ;
  print Data::TreeDumper::DumpTree($s, 'title', MAX_DEPTH => 1) ;
  
  #-------------------------------------------------------------------
  # OO interface
  #-------------------------------------------------------------------
  
  my $dumper = new Data::TreeDumper() ;
  $dumper->UseAnsi(1) ;
  $dumper->Maxdepth(2) ;
  $dumper->Filter(\&Data::TreeDumper::HashKeysSorter) ;
  
  print $dumper->Dump($s, "Using OO interface") ;
   
  #-------------------------------------------------------------------
  # native interface
  #-------------------------------------------------------------------
  
  print Data::TreeDumper::TreeDumper
  	(
  	  $s
  	, {
  	    FILTER      => \&Data::TreeDumper::HashKeysSorter
  	  , START_LEVEL => 1
  	  , USE_ASCII   => 0
  	  , MAX_DEPTH   => 2
  	  , TITLE       => "Using Native interface\n"
  	  }
  	) ;
  

Output

title:
|- A [H1]
|  |- a [H2]
|  |- bbbbbb = CODE(0x8139fa0) [C3]
|  |- c123 [C4 -> C3]
|  `- d [R5]
|     `- REF(0x8139fb8) [R5 -> C3]
|- ARRAY [A6]
|  |- 0 [S7] = elment_1
|  |- 1 [S8] = element_2
|  `- 2 [S9] = element_3
`- C [H10]
   `- b [H11]
      `- a [H12]
         |- a [H13]
         |- b = CODE(0x81ab130) [C14]
         `- c [S15] = 42
  

DESCRIPTION

Data::Dumper and other modules do a great job at dumping data structure but their output sometime takes more brain to understand than it takes to understand the data itself. When dumping big amounts of data, the output is overwelming and it's difficult to see the relationship between each piece of the dumped data.

Data::TreeDumper dumps data in a trees like fashion hopping for the output to be easier on the beholder's eye and brain. But it might as well be the opposite!

Address

Each node in the tree has a type (see Types bellow) and an address associated with it. The type and address are displayed to the right of the entry name within square brackets. The adresses are linearely incremented which should make it easier to locate data. If the entry is a reference to data already displayed, a -> is prepended to the entry's address.

|  |- bbbbbb = CODE(0x8139fa0) [C3]
|  |- c123 [C4 -> C3]
|  `- d [R5]
|     `- REF(0x8139fb8) [R5 -> C3]

Types

H: Hash, C: Code, A: Array, R: Reference,

O: Object, S: Scalar, RS: Scalar reference.

Empty Hash or Array

No structure is displayed for empty hashes or arrays, The Address contains the type.

|- A [S10] = string
|- EMPTY_ARRAY [A11]
|- B [S12] = 123

Configuration and Overrides

Data::TreeDumper has configuration options you can set to modify the output it generates. How to set the options depends on which Interface you use and is explained bellow. The configuration options are available in all the Interfaces and are the Native interface arguments.

The package and object oriented interface take overrides as trailing arguments. Those overrides are active within the current dump call only.

  ex:
  $Data::TreeDumper::Maxdepth = 2 ;
  
  # maximum depth set to 1 for the duration of the call only
  print Data::TreeDumper::DumpTree($s, 'title', MAX_DEPTH => 1) ;
	
  # maximum depth is 2
  print Data::TreeDumper::DumpTree($s, 'title') ;
  

DISPLAY_ROOT_ADDRESS

By default, Data::TreeDumper doesn't display the address of the root.

DISPLAY_ROOT_ADDRESS => 1 # show the root address

DISPLAY_ADDRESS

When the dumped data are not self referential, displaying the address of each node cluters the display. You can direct Data::TreeDumper to not display the node address by using:

DISPLAY_ADDRESS => 0

Filters

Data::TreeDumper can sort the tree nodes with a user defined sub.

FILTER => \&ReverseSort
FILTER => \&Data::TreeDumper::HashKeysSorter

The filter sub is passed three arguments, a reference to the node which is going to be displayed, it's depth (this allows you to selectively display elements at a certain depth) and an array reference containing the keys to be displayed (see filter chaining bellow) last argument can be undefined and can then be safely ignored.

The filter returns the node's type, an eventual new structure (see bellow) and a list of 'keys' to display. The keys are hash keys or array indexes.

If you set FILTER to \&Data::TreeDumper::HashKeysSorter, hashes will be sorted in alphabetic order.

Key removal

Entries can be removed by not returning their keys.

  my $s = {visible => '', also_visible => '', not_visible => ''} ;
  my $OnlyVisible = sub
  	{
  	my $s = shift ;
  	
	if('HASH' eq ref $s)
  		{
  		return('HASH', undef, grep {! /^not_visible/} keys %$s) ;
  		}
  		
  	return(Data::TreeDumper::DefaultNodesToDisplay($s)) ;
  	}
  	
  DumpTree($s, 'title', FILTER => $OnlyVisible) ;

Label changing

The label for a hash keys or an array index can be altered. This can be used to add visual information to the tree dump. Instead for returning the key name, return an array reference containing the key name and the label you want to display. You only need to return such a reference for the entries you want to change thus a mix of scalars and array ref is acceptable.

sub StarOnA
{
# hash entries matching /^a/i have '*' prepended

my $tree = shift ;

if('HASH' eq ref $tree)
	{
	my @keys_to_dump ;
	
	for my $key_name (keys %$tree)
		{
		if($key_name =~ /^a/i)
			{
			$key_name = [$key_name, "* $key_name"] ;
			}
			
		push @keys_to_dump, $key_name ;
		}
		
	return ('HASH', undef, @keys_to_dump) ;
	}
	
return (Data::TreeDumper::DefaultNodesToDisplay($tree)) ;
}

print Data::TreeDumper::DumpTree($s, "Entries matching /^a/i have '*' prepended", FILTER => \&StarOnA) ;

Structure replacement

It is possible to replace the whole data structure in a filter. This comes handy when you want to display a 'worked' version of the structure. You can even change the type of the data structure, for example changing an array to a hash.

  sub ReplaceArray
  {
  # replace arrays with hashes!!!
  
  my $tree = shift ;
  
  if('ARRAY' eq ref $tree)
  	{
	my $multiplication = $tree->[0] * $tree->[1] ;
	my $replacement = {MULTIPLICATION => $multiplication} ;
  	return('HASH', $replacement, keys %$replacement) ;
  	}
  	
  return (Data::TreeDumper::DefaultNodesToDisplay($tree)) ;
  }

  print Data::TreeDumper::DumpTree($s, 'replace arrays with hashes!', FILTER => \&ReplaceArray) ;

filter chaining

It is possible to chain filters. Data::TreeDumper exports CreateChainingFilter. CreateChainingFilter takes a list of filtering sub references. The filters must properly handle the third parameter passed to them.

Suppose you want to chaine a filter, that adds a star before each hash key label, with a filter that removes all (original) keys that match /^a/i.

sub AddStar
	{
	my $s = shift ;
	my $level = shift ;
	my $keys = shift ;
	
	if('HASH' eq ref $s)
		{
		$keys = [keys %$s] unless defined $keys ;
		
		my @new_keys ;
		
		for (@$keys)
			{
			if('' eq ref $_)
				{
				push @new_keys, [$_, "* $_"] ;
				}
			else
				{
				# another filter has changed the label
				push @new_keys, [$_->[0], "* $_->[1]"] ;
				}
			}
		
		return('HASH', undef, @new_keys) ;
		}
		
	return(Data::TreeDumper::DefaultNodesToDisplay($s)) ;
	} ;
	
sub RemoveA
	{
	my $s = shift ;
	my $level = shift ;
	my $keys = shift ;
	
	if('HASH' eq ref $s)
		{
		$keys = [keys %$s] unless defined $keys ;
		my @new_keys ;
		
		for (@$keys)
			{
			if('' eq ref $_)
				{
				push @new_keys, $_ unless /^a/i ;
				}
			else
				{
				# another filter has changed the label
				push @new_keys, $_ unless $_->[0] =~ /^a/i ;
				}
			}
		
		return('HASH', undef, @new_keys) ;
		}
		
	return(Data::TreeDumper::DefaultNodesToDisplay($s)) ;
	} ;

DumpTree($s, 'Chained filters', FILTER => CreateChainingFilter(\&AddStar, \&RemoveA)) ;

Start level

This configuration option controls whether the tree trunk is displayed or not.

START_LEVEL => 1:

$tree:
|- A [H1]
|  |- a [H2]
|  |- bbbbbb = CODE(0x8139fa0) [C3]
|  |- c123 [C4 -> C3]
|  `- d [R5]
|     `- REF(0x8139fb8) [R5 -> C3]
|- ARRAY [A6]
|  |- 0 [S7] = elment_1
|  |- 1 [S8] = element_2

START_LEVEL => 0:

$tree:
A [H1]
|- a [H2]
|- bbbbbb = CODE(0x8139fa0) [C3]
|- c123 [C4 -> C3]
`- d [R5]
   `- REF(0x8139fb8) [R5 -> C3]
ARRAY [A6]
|- 0 [S7] = elment_1
|- 1 [S8] = element_2

ASCII vs ANSI

You can direct Data:TreeDumper to output ANSI codes instead for ASCII characters. The display will be much nicer but takes slightly longer time (not significant for small data structures).

USE_ASCII => 0 # will use ANSI codes instead

Maximum depth of the dump

Controls the depth beyond which which we don't recurse into a structure. Default is -1, which means there is no maximum depth. This is useful to limit the amount of data displayed.

  MAX_DEPTH => 1 
	

Indentation

Every line of the tree dump will be appended with the value of INDENTATION.

INDENTATION => '   ' ;

Wrapping

Data::TreeDumper uses the Text::Wrap module to wrap your data to fit your display. Entries can be wrapped multiple times so they snuggly fit your screen.

|  |        |- 1 [S21] = 1
|  |        `- 2 [S22] = 2
|  `- 3 [O23 -> R17]
|- ARRAY_ZERO [A24]
|- B [S25] = scalar
|- Long_name Long_name Long_name Long_name Long_name Long_name 
|    Long_name Long_name Long_name Long_name Long_name Long_name
|    Long_name Long_name Long_name Long_name Long_name [S26] = 0

Zero width consol

When no consol exists, while redirecting to a file for example, Data::TreeDumper uses the variable VIRTUAL_WIDTH instead. Default is 120.

VIRTUAL_WIDTH => 120 ;

Interfaces

Data:TreeDumper has three interfaces. A 'package data' interface resembling Data::Dumper, an object oriented interface and the native interface. All interfaces return a string containing the dump.

Package Data (à la Data::Dumper)

Configuration Variables

$Data:TreeDumper::Startlevel         = 1 ;
$Data:TreeDumper::Useascii           = 1 ;
$Data:TreeDumper::Maxdepth           = -1 ;
$Data:TreeDumper::Indentation        = '' ;
$Data:TreeDumper::Virtualwidth       = 120 ;
$Data:TreeDumper::Displayrootaddress = 0 ;
$Data:TreeDumper::Displayaddress     = 1 ;
$Data:TreeDumper::Filter             = \&FlipEverySecondOne ;

Function

DumpTree uses the configuration variables defined above. It takes the following arguments

[1] structure_to_dump, this must be a reference
[2] title, a string to prepended to the tree
[3] overrides
print Data::TreeDumper::DumpTree($s, "title", MAX_DEPTH => 1) ;

Object oriented Methods

# constructor
my $dumper = new Data::TreeDumper(MAX_DEPTH => 1) ;

$dumper->UseAnsi(1) ;
$dumper->UseAscii(1) ;
$dumper->Maxdepth(2) ;
$dumper->SetIndentation('   ') ;
$dumper->SetVirtualWidth(80) ;
$dumper->SetFilter(\&Data::TreeDumper::HashKeysSorter) ;
$dumper->SetStartLevel(0) ;
$dumper->DisplayRootAddress(1) ;
$dumper->DisplayAddress(0) ;

$dumper->Dump($s, "Using OO interface", %OVERRIDES) ;
	

Native

Data::TreeDumper::TreeDumper
	(
	  $s
	, {
	    FILTER      => \&Data::TreeDumper::HashKeysSorter
	  , START_LEVEL => 1
	  , USE_ASCII   => 0
	  , MAX_DEPTH   => 2
	  , TITLE       => "Using Native interface"
	  }
	) ;

Bugs

None I know of in this release but plenty, lurking in the dark corners, waiting to be found.

Examples

Three examples files are included in the distribution.

usage.pl shows you how you can use Data::TreeDumper.

filters.pl shows you how you how to do advance filtering.

try_it.pl is meant as a scratch pad for you to try Data::TreeDumper.

EXPORT

DumpTree and CreateChainingFilter.

AUTHOR

Khemir Nadim ibn Hamouda. <nadim@khemir.net>

Thanks to Ed Avis for showing interest and pushing me to re-write the documentation.

Copyright (c) 2003 Nadim Ibn Hamouda el Khemir. All rights
reserved.  This program is free software; you can redis-
tribute it and/or modify it under the same terms as Perl
itself.

If you find any value in this module, mail me! All hints, tips, flammes and wishes are welcome at <nadim@khemir.net>.

SEE ALSO

The excellent Data::Dumper.

PBS: the Perl Build System from which Data::TreeDumper was extracted. Contact the author for more information about PBS.

1 POD Error

The following errors were encountered while parsing the POD:

Around line 1159:

Non-ASCII character seen before =encoding in '(à'. Assuming CP1252