File Coverage

blib/lib/XML/Handler/HTMLWriter.pm
Criterion Covered Total %
statement 96 108 88.8
branch 29 38 76.3
condition 13 15 86.6
subroutine 21 22 95.4
pod 1 1 100.0
total 160 184 86.9


line stmt bran cond sub pod time code
1             # $Id: HTMLWriter.pm,v 1.7 2003/03/30 09:47:44 matt Exp $
2              
3             package XML::Handler::HTMLWriter;
4              
5 12     12   91527 use strict;
  12         30  
  12         514  
6 12     12   69 use vars qw($VERSION @ISA);
  12         22  
  12         939  
7              
8             $VERSION = '2.01';
9              
10 12     12   12936 use XML::SAX::Writer ();
  12         697595  
  12         269  
11 12     12   12572 use HTML::Entities ();
  12         478685  
  12         2132  
12             @ISA = ('XML::SAX::Writer');
13              
14             sub new {
15 12     12 1 1712 my $class = shift;
16 12 50       89 my $opt = (@_ == 1) ? { %{shift()} } : {@_};
  0         0  
17              
18 12         49 $opt->{Writer} = 'XML::SAX::Writer::HTML';
19              
20 12         126 return XML::SAX::Writer->new($opt);
21              
22 0         0 my $opt = XML::SAX::Writer->new(@_);
23            
24 0         0 @ISA = (ref($opt));
25            
26 0         0 return bless $opt, $class;
27             }
28              
29             package XML::SAX::Writer::HTML;
30 12     12   105 use strict;
  12         22  
  12         368  
31 12     12   59 use XML::SAX::Writer::XML;
  12         16  
  12         373  
32 12     12   54 use vars qw(@ISA);
  12         18  
  12         18186  
33             # NB: this only works because of how hacky XML::SAX::Writer is ;-)
34             @ISA = ('XML::SAX::Writer::XML');
35              
36             sub print {
37 219     219   994 my $self = shift;
38 219         1005 $self->{Consumer}->output($self->{Encoder}->convert(join('', @_)));
39             }
40              
41             sub escape_attrib {
42 8     8   13 my $self = shift;
43 8         15 my $text = shift;
44 8         28 $text =~ s/&(?!\{)/&/g;
45 8         15 $text =~ s/"/"/g;
46 8         30 return $text;
47             }
48              
49             sub escape_url {
50 4     4   6 my $self = shift;
51 4         7 my $toencode = shift;
52 4         31 $toencode =~ s/&(?!\{)/&/g;
53 4         12 $toencode =~ s/([^a-zA-Z0-9_.&;-])/uc sprintf("%%%02x",ord($1))/eg;
  4         16  
54 4         14 return $toencode;
55             }
56              
57             sub escape_html {
58 63     63   91 my $self = shift;
59 63         541 return HTML::Entities::encode(join('', @_));
60             }
61              
62             my @html_tags = qw(
63             a abbr acronym address
64             applet area b base
65             basefont bdo big blockquote
66             body br button caption
67             center cite code col
68             colgroup dd del dfn
69             dir div dl dt
70             em fieldset font form
71             frame frameset h1 h2
72             h3 h4 h5 h6
73             head hr html i
74             iframe img input ins
75             isindex kbd label legend
76             li link map menu
77             meta noframes noscript object
78             ol optgroup option p
79             param pre q s
80             samp script select small
81             span strike strong style
82             sub sup table tbody
83             td textarea tfoot th
84             thead title tr tt
85             u ul var
86             );
87              
88             sub is_html_tag {
89 166     166   213 my $self = shift;
90 166         273 my $tag = lc(shift);
91            
92 166         14538 return grep /^$tag$/, @html_tags;
93             }
94              
95             my @empty_tags = qw(
96             area base basefont
97             br col frame hr img
98             input isindex link
99             meta param
100             );
101              
102             sub is_empty_tag {
103 47     47   72 my $self = shift;
104 47         79 my $tag = lc(shift);
105            
106 47         1286 return grep /^$tag$/, @empty_tags;
107             }
108              
109             my @uri_attribs = qw(
110             form/action
111             body/background
112             blockquote/cite
113             q/cite
114             del/cite
115             ins/cite
116             object/classid
117             object/codebase
118             applet/codebase
119             object/data
120             a/href
121             area/href
122             link/href
123             base/href
124             img/longdesc
125             frame/longdesc
126             iframe/longdesc
127             head/profile
128             script/src
129             input/src
130             frame/src
131             iframe/src
132             img/src
133             img/usemap
134             input/usemap
135             object/usemap
136             );
137              
138             sub is_url_attrib {
139 12     12   21 my $self = shift;
140 12         34 my $test = lc(shift);
141            
142 12         455 return grep /^$test$/, @uri_attribs;
143             }
144              
145             my @bool_attribs = qw(
146             input/checked
147             dir/compact
148             dl/compact
149             menu/compact
150             ol/compact
151             ul/compact
152             object/declare
153             script/defer
154             button/disabled
155             input/disabled
156             optgroup/disabled
157             option/disabled
158             select/disabled
159             textarea/disabled
160             img/ismap
161             input/ismap
162             select/multiple
163             area/nohref
164             frame/noresize
165             hr/noshade
166             td/nowrap
167             th/nowrap
168             textarea/readonly
169             input/readonly
170             option/selected
171             );
172              
173             sub is_boolean_attrib {
174 13     13   17 my $self = shift;
175 13         28 my $test = lc(shift);
176            
177 13         525 return grep /^$test$/, @bool_attribs;
178             }
179              
180             sub start_document {
181 12     12   672247 my ($self, $doc) = @_;
182            
183 12         119 undef $self->{FirstElement};
184            
185 12         122 $self->SUPER::start_document($doc);
186             }
187              
188             sub start_element {
189 52     52   44553 my ($self, $element) = @_;
190            
191 52         127 $element->{Parent} = $self->{Current_Element};
192 52         122 $self->{Current_Element} = $element;
193            
194 52 100       165 if (!$self->{FirstElement}) {
195 12         28 $self->{FirstElement}++;
196            
197 12 50 33     190 if (lc($element->{Name}) ne 'html' || $element->{NamespaceURI}) {
198 0         0 die "First element has to be ";
199             }
200            
201 12 50       79 if ($self->{DoctypePublic}) {
    50          
202 0         0 $self->print(qq({DoctypePublic}"));
203 0 0       0 if ($self->{DoctypeSystem}) {
204 0         0 $self->print(qq( "$self->{DoctypeSystem}"));
205             }
206 0         0 $self->print(">\n");
207             }
208             elsif ($self->{DoctypeSystem}) {
209 0         0 $self->print(qq({DoctypeSystem}">\n));
210             }
211             else {
212 12         62 $self->print(
213             qq(
214             "http://www.w3.org/TR/html4/strict.dtd">\n)
215             );
216             }
217             }
218            
219 52 100 100     546 if (!$element->{NamespaceURI} && $self->is_html_tag($element->{Name})) {
220             # HTML special cases...
221 47         206 $self->print("<$element->{Name}");
222            
223 47         452 foreach my $attr (values %{$element->{Attributes}}) {
  47         168  
224 13         49 my $test = "$element->{LocalName}/$attr->{Name}";
225 13 100       41 if ($self->is_boolean_attrib($test)) {
    100          
226 1         4 $self->print(" $attr->{Name}");
227             }
228             elsif ($self->is_url_attrib($test)) {
229 4         24 $self->print(" $attr->{Name}=\"", $self->escape_url($attr->{Value}), "\"");
230             }
231             else {
232 8         39 $self->print(" $attr->{Name}=\"",
233             $self->escape_attrib($attr->{Value}),
234             "\"");
235             }
236             }
237            
238 47         211 $self->print(">");
239            
240 47 100 100     793 if (lc($element->{LocalName}) eq 'script') {
    100          
241 1 50       6 $self->print("\n") unless $self->{NoScriptComment};
265             }
266 27         131 $self->print("{Name}>");
267             }
268             else {
269 5         31 $self->SUPER::end_element($element);
270             }
271             }
272              
273             sub characters {
274 67     67   23505 my ($self, $chars) = @_;
275            
276 67         114 my $element = $self->{Current_Element};
277            
278 67 100 100     310 if (!$element->{NamespaceURI} && $self->is_html_tag($element->{LocalName})) {
279 65 100       499 if (lc($element->{LocalName}) =~ /^(script|style)$/) {
280 2         6 $self->print($chars->{Data});
281             }
282             else {
283 63         188 $self->print($self->escape_html($chars->{Data}));
284             }
285             }
286             else {
287 2         18 $self->SUPER::characters($chars);
288             }
289             }
290              
291             sub processing_instruction {
292 1     1   50 my ($self, $pi) = @_;
293            
294 1 50       5 if (length $pi->{Data}) {
295 1         4 $self->print("{Target}, " ", $pi->{Data}, ">");
296             }
297             else {
298 0           $self->print("{Target}, ">");
299             }
300             }
301              
302             sub comment {
303 0     0     my ($self, $comment) = @_;
304             # strip comments?
305             }
306              
307             1;
308             __END__