File Coverage

blib/lib/HTML/Zoom/Parser/BuiltIn.pm
Criterion Covered Total %
statement 54 57 94.7
branch 15 18 83.3
condition 5 5 100.0
subroutine 10 11 90.9
pod 0 4 0.0
total 84 95 88.4


line stmt bran cond sub pod time code
1             package HTML::Zoom::Parser::BuiltIn;
2              
3 13     13   37472 use strictures 1;
  13         80  
  13         298  
4 13     13   925 use base qw(HTML::Zoom::SubObject);
  13         21  
  13         10123  
5              
6             sub html_to_events {
7 89     89 0 119 my ($self, $text) = @_;
8 89         131 my @events;
9 89     1208   419 _hacky_tag_parser($text => sub { push @events, $_[0] });
  1208         4262  
10 89         747 return \@events;
11             }
12              
13             sub html_to_stream {
14 29     29 0 34 my ($self, $text) = @_;
15 29         45 return $self->_zconfig->stream_utils
16 29         60 ->stream_from_array(@{$self->html_to_events($text)});
17             }
18              
19             # DO NOT BE AFRAID.
20             #
21             # Well, ok. Be afraid. A little. But this is lexing HTML with a regexp,
22             # not really parsing (since the structure nesting isn't handled here) so
23             # it's relatively not dangerous.
24             #
25             # Certainly it's not really any more or any less heinous than anything else
26             # I could do in a handful of lines of pure perl.
27              
28             sub _hacky_tag_parser {
29 89     89   108 my ($text, $handler) = @_;
30 89         424 $text =~ m{^([^<]*)}g;
31 89 50       293 if ( length $1 ) { # leading PCDATA
32 0         0 $handler->({ type => 'TEXT', raw => $1 });
33             }
34 89         1217 while (
35             $text =~ m{
36             (
37             (?:[^<]*) < (?:
38             ( / )? ( [^/!<>\s"'=]+ )
39             ( (?:"[^"]*"|'[^']*'|[^/"'<>])+? )?
40             |
41             (!-- .*? -- | ![^\-] .*? )
42             ) (\s*/\s*)? >
43             )
44             ([^<]*)
45             }sxg
46             ) {
47 673         1794 my ($whole, $is_close, $tag_name, $attributes, $is_special,
48             $in_place_close, $content)
49             = ($1, $2, $3, $4, $5, $6, $7, $8);
50 673 100       773 if ($is_special) {
51 1         3 $handler->({ type => 'SPECIAL', raw => $whole });
52             } else {
53 672         633 $tag_name =~ tr/A-Z/a-z/;
54 672 100       810 if ($is_close) {
55 317         766 $handler->({ type => 'CLOSE', name => $tag_name, raw => $whole });
56             } else {
57 355 100 100     1376 $attributes = '' if !defined($attributes) or $attributes =~ /^ +$/;
58 355   100     561 $handler->({
59             type => 'OPEN',
60             name => $tag_name,
61             is_in_place_close => $in_place_close,
62             _hacky_attribute_parser($attributes),
63             raw_attrs => $attributes||'',
64             raw => $whole,
65             });
66 355 100       665 if ($in_place_close) {
67 38         115 $handler->({
68             type => 'CLOSE', name => $tag_name, raw => '',
69             is_in_place_close => 1
70             });
71             }
72             }
73             }
74 673 100       1822 if (length $content) {
75 497         876 $handler->({ type => 'TEXT', raw => $content });
76             }
77             }
78             }
79              
80             sub _hacky_attribute_parser {
81 355     355   365 my ($attr_text) = @_;
82 355         256 my (%attrs, @attr_names);
83 355         1117 while (
84             $attr_text =~ m{
85             ([^\s\=\"\']+)(\s*=\s*(?:(")(.*?)"|(')(.*?)'|([^'"\s=]+)['"]*))?
86             }sgx
87             ) {
88 251         326 my $key = $1;
89 251         243 my $test = $2;
90 251 50       446 my $val = ( $3 ? $4 : ( $5 ? $6 : $7 ));
    100          
91 251         292 my $lckey = lc($key);
92 251 50       318 if ($test) {
93 251         321 $attrs{$lckey} = _simple_unescape($val);
94             } else {
95 0         0 $attrs{$lckey} = $lckey;
96             }
97 251         689 push(@attr_names, $lckey);
98             }
99 355         2294 (attrs => \%attrs, attr_names => \@attr_names);
100             }
101              
102             sub _simple_unescape {
103 251     251   240 my $str = shift;
104 251         263 $str =~ s/"/"/g;
105 251         246 $str =~ s/</
106 251         201 $str =~ s/>/>/g;
107 251         223 $str =~ s/&/&/g;
108 251         572 $str;
109             }
110              
111             sub _simple_escape {
112 130     130   159 my $str = shift;
113 130         209 $str =~ s/&/&/g;
114 130         227 $str =~ s/"/"/g;
115 130         128 $str =~ s/
116 130         146 $str =~ s/>/>/g;
117 130         482 $str;
118             }
119              
120 130     130 0 260 sub html_escape { _simple_escape($_[1]) }
121              
122 0     0 0   sub html_unescape { _simple_unescape($_[1]) }
123              
124             1;