patches from rt
[catagits/HTML-Zoom.git] / lib / HTML / Zoom / Parser / BuiltIn.pm
1 package HTML::Zoom::Parser::BuiltIn;
2
3 use strictures 1;
4 use base qw(HTML::Zoom::SubObject);
5
6 sub html_to_events {
7   my ($self, $text) = @_;
8   my @events;
9   _hacky_tag_parser($text => sub { push @events, $_[0] });
10   return \@events;
11 }
12
13 sub html_to_stream {
14   my ($self, $text) = @_;
15   return $self->_zconfig->stream_utils
16               ->stream_from_array(@{$self->html_to_events($text)});
17 }
18
19 sub _hacky_tag_parser {
20   my ($text, $handler) = @_;
21   $text =~ m{^([^<]*)}g;
22   if ( length $1 ) { # leading PCDATA
23       $handler->({ type => 'TEXT', raw => $1 });
24   }
25   while (
26     $text =~ m{
27       (
28         (?:[^<]*) < (?:
29             ( / )? ( [^/!<>\s"'=]+ )
30             ( (?:"[^"]*"|'[^']*'|[^/"'<>])+? )?
31         |   
32             (!-- .*? -- | ![^\-] .*? )
33         ) (\s*/\s*)? >
34       )
35       ([^<]*)
36     }sxg
37   ) {
38     my ($whole, $is_close, $tag_name, $attributes, $is_special,
39         $in_place_close, $content)
40       = ($1, $2, $3, $4, $5, $6, $7, $8);
41     if ($is_special) {
42       $handler->({ type => 'SPECIAL', raw => $whole });
43     } else {
44       $tag_name =~ tr/A-Z/a-z/;
45       if ($is_close) {
46         $handler->({ type => 'CLOSE', name => $tag_name, raw => $whole });
47       } else {
48         $attributes = '' if !defined($attributes) or $attributes =~ /^ +$/;
49         $handler->({
50           type => 'OPEN',
51           name => $tag_name,
52           is_in_place_close => $in_place_close,
53           _hacky_attribute_parser($attributes),
54           raw_attrs => $attributes||'',
55           raw => $whole,
56         });
57         if ($in_place_close) {
58           $handler->({
59             type => 'CLOSE', name => $tag_name, raw => '',
60             is_in_place_close => 1
61           });
62         }
63       }
64     }
65     if (length $content) {
66       $handler->({ type => 'TEXT', raw => $content });
67     }
68   }
69 }
70
71 sub _hacky_attribute_parser {
72   my ($attr_text) = @_;
73   my (%attrs, @attr_names);
74   while (
75     $attr_text =~ m{
76       ([^\s\=\"\']+)(\s*=\s*(?:(")(.*?)"|(')(.*?)'|([^'"\s=]+)['"]*))?
77     }sgx
78   ) {
79     my $key  = $1;
80     my $test = $2;
81     my $val  = ( $3 ? $4 : ( $5 ? $6 : $7 ));
82     my $lckey = lc($key);
83     if ($test) {
84       $attrs{$lckey} = _simple_unescape($val);
85     } else {
86       $attrs{$lckey} = $lckey;
87     }
88     push(@attr_names, $lckey);
89   }
90   (attrs => \%attrs, attr_names => \@attr_names);
91 }
92
93 sub _simple_unescape {
94   my $str = shift;
95   $str =~ s/&quot;/"/g;
96   $str =~ s/&lt;/</g;
97   $str =~ s/&gt;/>/g;
98   $str =~ s/&amp;/&/g;
99   $str;
100 }
101
102 sub _simple_escape {
103   my $str = shift;
104   $str =~ s/&/&amp;/g;
105   $str =~ s/"/&quot;/g;
106   $str =~ s/</&lt;/g;
107   $str =~ s/>/&gt;/g;
108   $str;
109 }
110
111 sub html_escape { _simple_escape($_[1]) }
112
113 sub html_unescape { _simple_unescape($_[1]) }
114
115 1;