XML::Filter::XML_Directory_Pruner - SAX2 filter for restricting the output of the XML::Directory::SAX


XML-Filter-XML_Directory_Pruner documentation Contained in the XML-Filter-XML_Directory_Pruner distribution.

Index


Code Index:

NAME

Top

XML::Filter::XML_Directory_Pruner - SAX2 filter for restricting the output of the XML::Directory::SAX

SYNOPSIS

Top

 use XML::SAX::Writer;
 use XML::Directory::SAX;
 use XML::Filter::XML_Directory_Pruner;

 my $output = "";

 my $writer = XML::SAX::Writer->new(Output=>\$output);
 my $pruner = XML::Filter::XML_Directory_Pruner->new(Handler=>$writer);

 $pruner->exclude(matching=>["(.*)\\.ph\$"]);
 $pruner->include(ending=>[".pm"]);

 my $directory = XML::Directory::SAX->new(Handler => $pruner,
                                          detail  => 2,
                                          depth   => 1);

 $directory->parse_dir($INC[0]);

DESCRIPTION

Top

XML::Filter::XML_Directory_Pruner is a SAX2 filter for restricting the output of the XML::Directory::SAX handler.

PACKAGE METHODS

Top

__PACKAGE__->mtype($file)

Return the media type, as defined by the MIME::Types package, associated with $file.

OBJECT METHODS

Top

$pkg = __PACKAGE__->new()

Inherits from XML::SAX::Base

$pkg->include(%args)

Include *only* that files that match either the starting or ending pattern.

Valid arguments are

$pkg->exclude(%args)

Exclude files with a particular name or pattern from being included in the directory listing.

Valid arguments are

$pkg->ima($what)

$pkg->current_level()

Read-only.

$pkg->skip_level()

$pkg->debug($int)

Read/write debugging flags.

By default, the package watches and performs actions if the debug level is greater than or equal to :

PRIVATE METHODS

Top

$pkg->start_element($data)

$pkg->end_element($data)

$pkg->_on_exit_end_element()

$pkg->characters($data)

$pkg->compare(\%data)

$pkg->_compare($data)

VERSION

Top

1.3

DATE

Top

July 20, 2002

AUTHOR

Top

Aaron Straup Cope

TO DO

Top

SEE ALSO

Top

XML::Directory::SAX

XML::SAX::Base

MIME::Types

LICENSE

Top

Copyright (c) 2002, Aaron Straup Cope. All Rights Reserved.

This is free software, you may use it and distribute it under the same terms as Perl itself.


XML-Filter-XML_Directory_Pruner documentation Contained in the XML-Filter-XML_Directory_Pruner distribution.
{

package XML::Filter::XML_Directory_Pruner;
use strict;

use Exporter;
use XML::SAX::Base;
use MIME::Types;

$XML::Filter::XML_Directory_Pruner::VERSION   = '1.3';
@XML::Filter::XML_Directory_Pruner::ISA       = qw (Exporter XML::SAX::Base);
@XML::Filter::XML_Directory_Pruner::EXPORT    = qw ();
@XML::Filter::XML_Directory_Pruner::EXPORT_OK = qw ();

my %__typeof = ();
my $__mtypes = undef;

sub mtype {
  my $pkg   = shift;
  my $fname = shift;

  #

  $fname =~ /^(.*)\.([^\.]+)$/;
  if (! $2) { return undef; }

  if (exists($__typeof{$2})) {
    return $__typeof{$2};
  }

  $__mtypes ||= MIME::Types->new()
    || return undef;


  #

  my $mime = $__mtypes->mimeTypeOf($2);
  
  if (! $mime) {
    $__typeof{$2} = undef;
    return $__typeof{$2};
  }
  
  #

  $__typeof{$2} = $mime->mediaType();
  return $__typeof{$2};
}

sub include {
    my $self = shift;
    my $args = { @_ };

    if (ref($args->{'include'})  eq "ARRAY") {
      push (@{$self->{__PACKAGE__.'__include'}},@{$args->{'include'}});
    }

    if ($args->{'matching'}) {
      $self->{__PACKAGE__.'__include_matching'} = (ref($args->{'matching'} eq "ARRAY")) ? 
	$args->{'matching'} : [$args->{'matching'}];
    }

    if (ref($args->{'starting'}) eq "ARRAY") {
      push (@{$self->{__PACKAGE__.'__include_starting'}},@{$args->{'starting'}});
    }

    if (ref($args->{'ending'}) eq "ARRAY") {
	push (@{$self->{__PACKAGE__.'__include_ending'}},@{$args->{'ending'}});
    }

    if ($args->{'directories'}) {
      $self->{__PACKAGE__.'__include_subdirs'} = 1;
    }

    return 1;
}

sub exclude {
    my $self = shift;
    my $args  = { @_ };

    if (ref($args->{'exclude'})  eq "ARRAY") {
      push (@{$self->{__PACKAGE__.'__exclude'}},@{$args->{'exclude'}});
    }

    if ($args->{'matching'}) {
      $self->{__PACKAGE__.'__exclude_matching'} = (ref($args->{'matching'}) eq "ARRAY") ? 
	$args->{'matching'} : [ $args->{'matching'}];
    }

    if (ref($args->{'starting'}) eq "ARRAY") {
      push (@{$self->{__PACKAGE__.'__exclude_starting'}},@{$args->{'starting'}});
    }

    if (ref($args->{'ending'})   eq "ARRAY") {
      push (@{$self->{__PACKAGE__.'__exclude_ending'}},@{$args->{'ending'}});
    }

    $self->{__PACKAGE__.'__exclude_subdirs'} = $args->{'directories'};
    $self->{__PACKAGE__.'__exclude_files'}   = $args->{'files'};
    return 1;
}

sub ima {
  my $self = shift;
  my $what = shift;

  if ($what) {
    $self->{__PACKAGE__.'__ima'} = $what;
  }

  return $self->{__PACKAGE__.'__ima'};
}

sub current_level {
  my $self = shift;
  return $self->{__PACKAGE__.'__level'};
}

sub skip_level {
  return $_[0]->{__PACKAGE__.'__skip'};
}

sub debug {
  my $self = shift;
  my $debug = shift;

  if (defined($debug)) {
    $self->{__PACKAGE__.'__debug'} = ($debug) ? (int($debug)) ? $debug : 1 : 0;
  }

  return $self->{__PACKAGE__.'__debug'};
}

sub start_element {
  my $self  = shift;
  my $data  = shift;

  $self->on_enter_start_element($data);
  $self->compare($data);

  unless ($self->{__PACKAGE__.'__skip'}) {
    $self->{__PACKAGE__.'__last'} = $data->{'Name'};
    $self->SUPER::start_element($data);
  }

  return 1;
}

sub on_enter_start_element {
  my $self = shift;
  my $data = shift;

  $self->{__PACKAGE__.'__level'} ++;

#  if ($data->{Name} =~ /^(directory|file)$/) {
#    $self->{__PACKAGE__.'__'.$1} ++;
#    map { print " "; } (0..$self->{__PACKAGE__.'__'.$1});
#    print $self->{__PACKAGE__.'__'.$1} ." [$1] $data->{Attributes}->{'{}name'}->{Value} ".__PACKAGE__."\n";
#  }

  if ($self->debug() >= 2) {
    map { print STDERR " "; } (0..$self->current_level);
    print STDERR "[".$self->current_level."] $data->{Name} : ";
    # Because sometimes auto-vivification
    # is not what you want.
    if (exists($data->{Attributes}->{'{}name'})) {
      print STDERR $data->{Attributes}->{'{}name'}->{Value};
    }

    print STDERR "\n";
  }

  return 1;
}

sub end_element {
  my $self = shift;
  my $data = shift;

  unless ($self->{__PACKAGE__.'__skip'}) {
    $self->SUPER::end_element($data);
  }

  $self->on_exit_end_element($data);
  return 1;
}

sub on_exit_end_element {
  my $self = shift;
  my $data = shift;

  if ($self->{__PACKAGE__.'__skip'} == $self->{__PACKAGE__.'__level'}) {
    $self->{__PACKAGE__.'__skip'} = 0;
  }

  if ($data->{Name} =~ /^(directory|file)$/) {
    $self->{__PACKAGE__.'__'.$1} --;
  }

  $self->{__PACKAGE__.'__level'} --;
  return 1;
}

sub characters {
  my $self = shift;
  my $data = shift;

  unless ($self->{__PACKAGE__.'__skip'}) {
    $self->SUPER::characters($data);
  }
  
  return 1;
}

sub compare {
  my $self = shift;
  my $data = shift;

  if ($data->{'Name'} =~ /^(file|directory)$/) {
    # map { print " "; } (0..$self->{__PACKAGE__.'__'.$1});
    # print $self->{__PACKAGE__.'__'.$1} ." <$1> $data->{Attributes}->{'{}name'}->{Value} ($self->{__PACKAGE__.'__skip'})\n";

    if (! $self->{__PACKAGE__.'__skip'}) {
      $self->{__PACKAGE__.'__ima'} = $1;
      $self->_compare($data->{Attributes}->{'{}name'}->{Value});
    }
  }

  return 1;
}

sub _compare {
  my $self = shift;
  my $data = shift;

  my $ok = 1;

  # Note the check on __level. We have to do
  # this, so that filtering the output for
  # /foo/bar won't fail with :
  #
  # 101 ->./dir-machine
  # 1 dirtree
  #  2 head
  #   3 path
  #   3 details
  #   3 depth
  # Comparing 'bar' (directory)...failed directory test...'0' (2)

  if ($self->{__PACKAGE__.'__level'} == 2) { return 1; }

  #

  if ($self->{__PACKAGE__.'__ima'} eq "directory") {
    if (($ok) && ($self->{__PACKAGE__.'__exclude_subdirs'})) {
      print STDERR "10 - EXCLUDING $data BECAUSE I AM A DIRECTORY\n"
	if ($self->debug() >= 3);
      $ok = 0;
    }
  }

  if (($ok) && ($self->{__PACKAGE__.'__ima'} eq "file" && $self->{__PACKAGE__.'__exclude_files'})) {
    print STDERR "20 - EXCLUDING $data BECAUSE I AM A FILE\n"
      if ($self->debug() >= 3);
    $ok = 0;
  }

  #

  if (($ok) && ($self->{__PACKAGE__.'__include_matching'} eq "ARRAY")) {
    foreach my $pattern (@{$self->{__PACKAGE__.'__include_matching'}}) {
      $ok = ($data =~ /$pattern/) ? 1 : 0;

      if ($ok) {
	print STDERR "20 - INCLUDING $data BECAUSE IT MATCHES PATTERN '$pattern'\n"
	  if ($self->debug() >= 3);
	last;
      }
    }
  }

  if (($ok) && (ref($self->{__PACKAGE__.'__include'}) eq "ARRAY")) {
    foreach my $match (@{$self->{__PACKAGE__.'__include'}}) {
      $ok = ($data =~ /^($match)$/) ? 0 : 1;

      if ($ok) {
	print STDERR "30 - INCLUDING $data BECAUSE IT MATCHES '$match'\n"
	  if ($self->debug() >= 3);
	last;
      }
    }
  }

  if (($ok) && (ref($self->{__PACKAGE__.'__include_starting'}) eq "ARRAY")) {
    foreach my $match (@{$self->{__PACKAGE__.'__include_starting'}}) {
      $ok = ($data =~ /^($match)(.*)$/) ? 1 : 0;

      if ($ok) {
	print STDERR "40 - INCLUDING $data BECAUSE IT STARTS WITH '$match'\n"
	  if ($self->debug() >= 3);
	last;
      }
    }
  }

  if (($ok) && (ref($self->{__PACKAGE__.'__include_ending'}) eq "ARRAY")) {
    foreach my $match (@{$self->{__PACKAGE__.'__include_ending'}}) {
      $ok = ($data =~ /^(.*)($match)$/) ? 1 : 0;

      if ($ok) {
	print STDERR "50 - INCLUDING $data BECAUSE IT ENDS WITH '$match'\n"
	  if ($self->debug() >= 3);
	last;
      }
    }
  }

  #

  if (($ok) &&(ref($self->{__PACKAGE__.'__exclude_matching'}) eq "ARRAY")) {

    foreach  my $pattern (@{$self->{__PACKAGE__.'__exclude_matching'}}) {

      print STDERR "25 - COMPARING '$data' w/ '$pattern'\n"
	if ($self->debug() >= 4);

      $ok = ($data =~ /$pattern/) ? 0 : 1;

      if (! $ok) {
	print STDERR "30 - EXCLUDING $data BECAUSE IT MATCHES PATTERN '$pattern'\n"
	  if ($self->debug() >= 3);

	last;
      }
    }
  }

  if (($ok) && (ref($self->{__PACKAGE__.'__exclude'}) eq "ARRAY")) {
    foreach my $match (@{$self->{__PACKAGE__.'__exclude'}}) {
      $ok = ($data =~ /^($match)$/) ? 0 : 1;

      if (! $ok) {
	print STDERR "40 - EXCLUDING $data BECAUSE IT MATCHES '$match'\n"
	  if ($self->debug() >= 3);
	last;
      }
    }
  }

  if (($ok) && (ref($self->{__PACKAGE__.'__exclude_starting'}) eq "ARRAY")) {
    foreach my $match (@{$self->{__PACKAGE__.'__exclude_starting'}}) {
      $ok = ($data =~ /^($match)(.*)$/) ? 0 : 1;

      if (! $ok) {
	print STDERR "50 - EXCLUDING $data BECAUSE IT STARTS WITH '$match'\n"
	  if ($self->debug() >= 3);
	last;
      }
    }
  }

  if (($ok) && (ref($self->{__PACKAGE__.'__exclude_ending'}) eq "ARRAY")) {
    foreach my $match (@{$self->{__PACKAGE__.'__exclude_ending'}}) {
      $ok = ($data =~ /^(.*)($match)$/) ? 0 : 1;

      if (! $ok) {
	print STDERR "60 - EXCLUDING $data BECAUSE IT ENDS WITH '$match'\n"
	  if ($self->debug() >= 3);
	last;
      }
    }
  }

  #

  if (! $ok) {
    print STDERR "SKIPPING '$data' at $self->{__PACKAGE__.'__level'}\n"
      if ($self->debug() >= 2);

    $self->{__PACKAGE__.'__skip'} = $self->{__PACKAGE__.'__level'};
  }

  return 1;
}


return 1;

}