File Coverage

blib/lib/HTML/LinkFilter.pm
Criterion Covered Total %
statement 31 31 100.0
branch n/a
condition n/a
subroutine 8 8 100.0
pod 4 4 100.0
total 43 43 100.0


line stmt bran cond sub pod time code
1             package HTML::LinkFilter;
2 10     10   16486 use strict;
  10         22  
  10         376  
3 10     10   49 use warnings;
  10         17  
  10         277  
4 10     10   10072 use HTML::Parser;
  10         69715  
  10         10138  
5              
6             our $VERSION = "0.03";
7              
8             ## The html tags which might have URLs
9             # the master list of tagolas and required attributes (to constitute a link)
10             our %TAGS = ( # Copied from HTML::LinkExtractor 0.13
11             a => [qw( href )],
12             applet => [qw( archive code codebase src )],
13             area => [qw( href )],
14             base => [qw( href )],
15             bgsound => [qw( src )],
16             blockquote => [qw( cite )],
17             body => [qw( background )],
18             del => [qw( cite )],
19             div => [qw( src )], # IE likes it, but don't know where it's documented
20             embed => [qw( pluginspage pluginurl src )],
21             form => [qw( action )],
22             frame => [qw( src longdesc )],
23             iframe => [qw( src )],
24             ilayer => [qw( background src )],
25             img => [qw( dynsrc longdesc lowsrc src usemap )],
26             input => [qw( dynsrc lowsrc src )],
27             ins => [qw( cite )],
28             isindex => [qw( action )], # real oddball
29             layer => [qw( src )],
30             link => [qw( src href )],
31             object => [qw( archive classid code codebase data usemap )],
32             q => [qw( cite )],
33             script => [qw( src )], # HTML::Tagset has 'for' ~ it's WRONG!
34             sound => [qw( src )],
35             table => [qw( background )],
36             td => [qw( background )],
37             th => [qw( background )],
38             tr => [qw( background )],
39             ## the exotic cases
40             meta => undef,
41             '!doctype' => [qw( url )], # is really a process instruction
42             );
43              
44             ### HTML::Parser method, not for __PACKAGE__.
45             my $default_h_sub = sub {
46             my( $self, $tagname, $original ) = @_;
47              
48             push @{ $self->{link_filter}{tags} }, $original;
49              
50             return;
51             };
52              
53             ### HTML::Parser method, not for __PACKAGE__.
54             my $start_h_sub = sub {
55             my( $self, $tagname, $attr_ref, $original ) = @_;
56              
57             unless ( exists $TAGS{ $tagname } ) {
58             push @{ $self->{link_filter}{tags} }, $original
59             and return;
60             }
61              
62             unless ( grep { my $name = $_; grep { $_ eq $name } @{ $TAGS{ $tagname } } } keys %{ $attr_ref } ) {
63             push @{ $self->{link_filter}{tags} }, $original
64             and return;
65             }
66              
67             unless ( $self->{link_filter}{cb} ) {
68             push @{ $self->{link_filter}{tags} }, $original
69             and return;
70             }
71              
72             foreach my $attr ( keys %{ $attr_ref } ) {
73             next
74             unless grep { $_ eq $attr } @{ $TAGS{ $tagname } };
75              
76             my $new = $self->{link_filter}{cb}->(
77             $tagname, $attr, $attr_ref->{ $attr }, $attr_ref,
78             );
79              
80             $attr_ref->{ $attr } = $new
81             if defined $new;
82             }
83              
84             my $tag = do {
85             my $build = q{};
86             my $is_xhtml = grep { $_ eq q{/} } keys %{ $attr_ref };
87             my $attr = join q{ }, map {
88             join q{=}, $_, join q{}, q{"}, $attr_ref->{ $_ }, q{"},
89             } grep { $_ ne q{/} } sort keys %{ $attr_ref };
90              
91             if ( $attr && $is_xhtml ) {
92             $build = "<$tagname $attr />";
93             }
94             elsif ( $attr && ! $is_xhtml ) {
95             $build = "<$tagname $attr>";
96             }
97             elsif ( ! $attr && $is_xhtml ) {
98             $build = "<$tagname />";
99             }
100             else {
101             $build = "<$tagname>";
102             }
103              
104             if ( chomp $original ) {
105             $build .= "\n";
106             }
107              
108             $build;
109             };
110              
111             push @{ $self->{link_filter}{tags} }, $tag;
112              
113             return $self;
114             };
115              
116             sub new {
117 8     8 1 1321 my $class = shift;
118 8         25 my %param = @_;
119              
120 8         97 my $self = bless \%param, $class;
121              
122 8         86 my $p = HTML::Parser->new(
123             api_version => 3,
124             start_h => [
125             $start_h_sub, "self, tagname, attr, text",
126             ],
127             default_h => [
128             $default_h_sub, "self, tagname, text",
129             ],
130             );
131              
132 8         725 $p->{link_filter} = $self;
133 8         43 $self->{p} = $p;
134 8         33 $self->_init_tags;
135              
136 8         20 return $self;
137             }
138              
139             sub change {
140 15     15 1 4033 my $self = shift;
141 15         25 my( $html, $callback_sub ) = @_;
142              
143 15         32 $self->_init_tags;
144 15         21 $self->{cb} = $callback_sub;
145 15         131 $self->{p}->parse( $html );
146 15         75 $self->{p}->eof;
147              
148 15         29 return $self;
149             }
150              
151             sub _init_tags {
152 23     23   32 my $self = shift;
153 23         58 $self->{tags} = [ ];
154 23         47 return $self;
155             }
156              
157             sub tags {
158 15     15 1 88 return shift->{tags};
159             }
160              
161             sub html {
162 15     15 1 53 my $self = shift;
163              
164 15         20 return join q{}, @{ $self->tags };
  15         27  
165             }
166              
167             1;
168             __END__