geek talk: a problem and the solution with Tree::DAG_Node perl module

Tree structures are inherently complex and more difficult to handle in a program.  This is why I was happy to find a perl module called Tree::DAG_Node which helps to simplify the work required to deal with trees.  However, before I could fully finish a program dealing with the trees, I ecountered a roadblock (and the solution) which I go into more details below:

I was programming with the Tree::DAG_Node perl module and I was able to get it to work up to a point where it just dropped the ball or maybe I am blind to what I am doing wrong.

I am doing a walkdown using callback down a DAG tree.  When I hit a certain node, I wanted to process the data further.  The problem is that when I insert a foreach statement, the walkdown stops traversing the tree.

Testing the DAG Tree output:

print map "$_\n" , @{$root->draw_ascii_tree};
produces the following diagram so I know the Tree creation was successful:
              |
<Shipment and Tracking Data>
              |
          <2000886>
              |
          <INV1000>
      /————–\
      |                  |
<TrackUPS1234> <TrackUPS4321>

using the following code:

my $found_customer = 0;
$root->walk_down({
   callback => sub {
        my $node = shift;
        print "  " x $_[0]->{_depth};
        if ( $_[0]->{_depth} eq 0 ) {
                print "\n" ;
        }
        elsif ( $_[0]->{_depth} eq 1 ) {
                if ( $found_customer eq 1 )  {
                        print "write footer email\n";
                        print "  " x $_[0]->{_depth};
                }
                print "header email – Customer\# " . $node->name . " " . $node-> attributes->{‘name’}. " "  .  $node->attributes->{’email’} . "\n" ;
                $found_customer = 1;
$f0 = "";
$f1 = "";
$f2 = "";
$f3 = "";
$f4 = "";
@customized_letter_lines = ();
$f0 = $node->attributes->{’email’};
$f1 = $node->attributes->{‘name’};
$f2 = $node->name;

my @letter_lines = @header_lines;

        }
        elsif ( $_[0]->{_depth} eq 2 ) {
                print "Invoice  " . $node->name . "\n";
                $f3 = $node->name;
        }
        elsif ( $_[0]->{_depth} eq 3 ) {
                print " Track " . $node->name . "\n";
                $f4 = $node->name;
        }
        else {
                1
        }

    },
    _depth => 0
});

if ( $found_customer eq 1 )  {
  print "  write footer email\n";
}

output is:

  header email – Customer# 2000886 Happy, Inc. jd@dawnsign.com
    Invoice  INV1000
       Track TrackUPS1234
       Track TrackUPS4321
  write footer email

so far so good, but when I add the foreach statement:


my @letter_lines = @header_lines;
#insert the foreach statement
foreach my $letter_line (@letter_lines) {
}
#end insert the foreach statement

The output is now:

  header email – Customer# 2000886 Happy Inc. jd@dawnsign.com
  write footer email

As you can see, it did not traverse the Invoice(INV) and Track nodes.

I got an answer back from Roel van der Steen (the developer behind FrameMaker::MifTree module which makes extensive use of Tree::DAG_Node):

From the Tree::DAG_Node documentation:
   "
   This function [the callback function] must
   return true or false — if false, it will
   block the next step: […]
   "

Your problem is that the foreach loop is the last statement executed in the callback function, and the foreach returns undef, which evaluates to false, so the walk_down procedure stops traversing. Adding a "return 1" corrects this problem. In fact, when using callback, make sure you always explicitly set its return value with a "return" statement.

Problem solved!

This entry was posted in Programming. Bookmark the permalink.