XML::Filter::XML_Directory_2::Base - base class for creating XML::Directory to something else SAX filters.


XML-Filter-XML_Directory_2-Base documentation Contained in the XML-Filter-XML_Directory_2-Base distribution.

Index


Code Index:

NAME

Top

XML::Filter::XML_Directory_2::Base - base class for creating XML::Directory to something else SAX filters.

SYNOPSIS

Top

 package XML::Filter::XML_Directory_2Foo;
 use base qw (XML::Filter::XML_Directory_2::Base);

DESCRIPTION

Top

Base class for creating XML::Directory to something else SAX filters.

This class inherits from XML::Filter::XML_Directory_Pruner.

PACKAGE METHODS

Top

__PACKAGE__->attributes(\%args)

This is a simple helper method designed to save typing.

Value arguments are

Returns a hash with a single key named Attributes whose value is a hash ref for passing to the XML::SAX::Base::start_element method.

This method does not support namespaces (yet.)

OBJECT METHODS

Top

$pkg->encoding($type)

$pkg->set_encoding($type)

Alias for encoding

$pkg->exclude_root($bool)

By default, XML::Directory will include the directory you pass to the XML::Directory(::SAX)::parse_dir method.

You can use this method to instruct your filter to only include the contents of the root directory and not the directory itself.

$pkg->start_level()

Read-only.

$pkg->cwd()

Read-only.

$pkg->current_directory()

Short-cut (ahem) for $pkg->cwd()

$pkg->current_location()

Returns the current location relative to the directory root

$pkg->set_handlers(\%args)

Define one or more valid SAX2 thingies to be called when your package encounters a specific event. Thingies are like any other SAX2 thingy with a few requirements :

 # If this...

 my $writer = XML::SAX::Writer->new();
 my $rss = XML::Filter::XML_Directory_2RSS->new(Handler=>$writer);
 $rss->set_handlers({title=>MySAX::TitleHandler->new(Handler=>$writer)});

 # Called this...

 package MySAX::TitleHandler;
 use base qw (XML::SAX::Base);

 sub parse_uri {
    my ($pkg,$path,$title) = @_;

    $pkg->SUPER::start_prefix_mapping({Prefix=>"me",NamespaceURI=>"..."});
    $pkg->SUPER::start_element({Name=>"me:woot"});
    $pkg->SUPER::characters({Data=>&get_title_from_file($path)});
    $pkg->SUPER::end_element({Name=>"me:woot"});
    $pkg->SUPER::end_prefix_mapping({Prefix=>"me"});
 }

 # Then the output would look like this...

 <item>
  <title>
   <me:woot xmlns:me="...">I Got My Title From the File</me:woot>
  </title>
  <link>...</link>
  <description />
 </item>

Valid events are defined on a per class basis. Your class needs to define a handler_events package method that returns a list of valid handler events.

Handlers have a higher precedence than callbacks.

$pkg->retrieve_handler($event_name)

Returns the handler (object) associated with $event_name

$pkg->set_callbacks(\%args)

Register one of more callbacks for your document.

Callbacks are like handlers except that they are code references instead of SAX2 thingies.

A code reference might be used to munge the link value of an item into a URI suitable for viewing in a web browser.

Valid events are defined on a per class basis. Your class needs to define a callback_events package method that returns a list of valid callback events.

Callbacks have a lower precedence than handlers.

$pkg->retrieve_callback($event_name)

Return the callback (code reference) associated with $event_name.

$pkg->generate_id()

Returns an MD5 hash of the path, relative to the root, for the current file

$pkg->build_uri(\%data)

Returns the absolute path for the current document.

$pkg->on_enter_start_element(\%data)

This method should be called as the first action in your class' start_element method. It will perform a number of helper actions, like keeping track of the current node level and the absolute path of the current document.

Additionalllly it will check to see if the current node should be included or excluded based on rules defined by XML::Filter::XML_Directory_Pruner.

Returns true if everything is honky-dorry.

Returns false if the current node is to be excluded or if the document has not "started" (see docs for the start_level method.)

$pkg->on_enter_end_element(\%data)

$pkg->on_exit_end_element(\%data)

This method should be called as the first action in your class' end_element method.

$pkg->on_characters(\%data)

This method should be called as the first action in your class' characters method.

VERSION

Top

1.4.4

DATE

Top

July 22, 2002

AUTHOR

Top

Aaron Straup Cope

TO DO

Top

SEE ALSO

Top

XML::Directory::SAX

XML::Filter::XML_Directory_Pruner

LICENSE

Top

Copright (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_2-Base documentation Contained in the XML-Filter-XML_Directory_2-Base distribution.
{

package XML::Filter::XML_Directory_2::Base;
use strict;

use Carp;
use Exporter;
use Digest::MD5 qw (md5_hex);
use XML::Filter::XML_Directory_Pruner '1.3';

$XML::Filter::XML_Directory_2::Base::VERSION   = '1.4.4';
@XML::Filter::XML_Directory_2::Base::ISA       = qw ( XML::Filter::XML_Directory_Pruner );
@XML::Filter::XML_Directory_2::Base::EXPORT    = qw ();
@XML::Filter::XML_Directory_2::Base::EXPORT_OK = qw ();

sub attributes {
  my $pkg   = shift;
  my %attrs = @_;
  
  my %saxtributes = ();
  
  foreach (sort keys %attrs) {
    $saxtributes{"{}$_"} = { 
                            Name         => $_,
                            Value        => $attrs{$_},
                            Prefix       => "",
                            LocalName    => $_,
                            NameSpaceURI => "",
                           };
  }

  return (Attributes=>\%saxtributes);
}

sub encoding {
  my $self = shift;
  my $type = shift;

  if ($type) {
    $self->{__PACKAGE__.'__type'} = $type;
  }

  return $self->{__PACKAGE__.'__type'} || "UTF-8";
}

sub set_encoding {
  my $self = shift;
  $self->encoding(@_);
}

sub exclude_root {
  my $self = shift;
  my $bool = shift;

  if (defined($bool)) {
    $self->{__PACKAGE__.'__includeroot'} = ($bool) ? 0 : 1;
  }

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

sub start_level {
  my $self = shift;
  return $self->{__PACKAGE__.'__start'};
}

sub cwd {
  my $self = shift;
  return $self->{__PACKAGE__.'__cwd'};
}

sub current_directory {
  return $_[0]->cwd();
}

sub current_location {
  my $self = shift;
  return $self->{__PACKAGE__.'__loc'};
}

sub handler_events { return (); }

sub set_handlers {
  my $self = shift;
  my $args = shift;

  if (ref($args) ne "HASH") {
    return undef;
  }

  foreach ($self->handler_events()) {
    next if (! $args->{$_});

    if (! UNIVERSAL::can($args->{$_},"parse_uri")) {
      carp "Handler must define a 'parse_uri' method.\n";
      next;
    }

    $self->{__PACKAGE__.'__handlers'}{$_} = $args->{$_};
  }

  return 1;
}

sub retrieve_handler {
  my $self = shift;
  return $self->{__PACKAGE__.'__handlers'}{$_[0]};
}

sub callback_events { return (); }

sub set_callbacks {
  my $self = shift;
  my $args = shift;

  if (ref($args) ne "HASH") {
    return undef;
  }

  foreach ($self->callback_events()) {
    next if (! $args->{$_});

    if (ref($args->{$_}) ne "CODE") {
      carp "Not a CODE reference";
      return undef;
    }

    $self->{__PACKAGE__.'__callbacks'}{$_} = $args->{$_};
  }

  return 1;
}

sub retrieve_callback {
  my $self = shift;
  return $self->{__PACKAGE__.'__callbacks'}{$_[0]};
}

sub generate_id {
  my $self = shift;
  return "ID".&md5_hex($self->{__PACKAGE__.'__loc'});
}

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

  my $uri = $self->{__PACKAGE__.'__path'}.$self->{__PACKAGE__.'__cwd'};

  if ($data->{Name} eq "file") {
    $uri .= "/$data->{Attributes}->{'{}name'}->{Value}";
  }

  return $uri;
}

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

  my $link = $self->build_uri($data);

  if (my $c = $self->retrieve_callback("link")) {
    $link = &$c($link);
  }

  return $link;
}

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

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

  if ($data->{Name} eq "head") {
      $self->{__PACKAGE__.'__head'} = 1;
  }

  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->{__PACKAGE__.'__start'}) && ($data->{Name} =~ /^(file|directory)$/)) {

    if (! exists($self->{__PACKAGE__.'__includeroot'})) {
      $self->{__PACKAGE__.'__start'} = $self->current_level();
      return 1;
    }

    else {

      if ((! $self->{__PACKAGE__.'__includeroot'}) &&
	  (($self->{__PACKAGE__.'__file'} == 1) || ($self->{__PACKAGE__.'__directory'} == 2))) {

	$self->{__PACKAGE__.'__start'} = $self->current_level();
	$self->grow_cwd($data);

	$self->compare($data);

	if (! $self->skip_level()) {
	  return 1;
	}

	$self->prune_cwd($data);
	return 0;
      }
    }

  }

  #

  if (! $self->{__PACKAGE__.'__start'}) {
    return 0;
  }

  $self->compare($data);

  if ($self->skip_level()) {
    return 0;
  }

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

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

  if ($data->{Name} eq "head") {
    $self->{__PACKAGE__.'__head'} = 0;
  }

  return 1;
}

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

  unless ($self->skip_level()) {
    $self->prune_cwd($data);
  }

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

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

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

  if ($self->{__PACKAGE__.'__head'}) {
    $self->{ __PACKAGE__.'__'.$self->{__PACKAGE__.'__last'} } ||= $data->{Data};
  }

  return 1;
}

# =head2 $pkg->grow_cwd(\%data)
#
# =cut

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

  if ($data->{Name} =~ /^(file|directory)$/) {
    $self->{__PACKAGE__.'__loc'} .= "/$data->{Attributes}->{'{}name'}->{Value}";
  }

  if ($data->{Name} eq "directory") {
    $self->{__PACKAGE__.'__cwd'} .= "/$data->{Attributes}->{'{}name'}->{Value}";
    # print STDERR $self->{__PACKAGE__.'__cwd'}."\n";
  }

  return 1;
}

# =head2 $pkg->prune_cwd(\%data)
#
# =cut

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

  if ($data->{Name} =~ /^(file|directory)$/) {
    $self->{__PACKAGE__.'__loc'} =~ s/^(.*)\/([^\/]+)$/$1/;
  }

  if ($data->{Name} eq "directory") {
    $self->{__PACKAGE__.'__cwd'} =~ s/^(.*)\/([^\/]+)$/$1/;
    # print STDERR "[prune] ".$self->{__PACKAGE__.'__cwd'}."\n";
  }


  return 1;
}

return 1;

}