File Coverage

blib/lib/HTML/TableContent/Parser.pm
Criterion Covered Total %
statement 110 117 94.0
branch 44 44 100.0
condition 5 6 83.3
subroutine 20 23 86.9
pod 7 13 53.8
total 186 203 91.6


line stmt bran cond sub pod time code
1             package HTML::TableContent::Parser;
2              
3 18     18   131 use Moo;
  18         43  
  18         145  
4              
5             our $VERSION = '1.00';
6              
7             extends 'HTML::Parser';
8              
9 18     18   14685 use HTML::TableContent::Table;
  18         63  
  18         28862  
10              
11             has [qw(current_tables nested caption_selectors)] => (
12             is => 'rw',
13             lazy => 1,
14             clearer => 1,
15             default => sub { [] },
16             );
17              
18             has [qw(current_table current_element selected)] => (
19             is => 'rw',
20             lazy => 1,
21             clearer => 1,
22             );
23              
24             has options => (
25             is => 'ro',
26             lazy => 1,
27             builder => 1,
28             );
29              
30 2938 100   2938 0 4166 sub has_caption_selector { return scalar @{ $_[0]->caption_selectors } ? 1 : 0 }
  2938         44495  
31              
32 8679     8679 0 15583 sub count_nested { return scalar @{ $_[0]->nested }; }
  8679         133714  
33              
34 7809 100   7809 0 14161 sub has_nested { return $_[0]->count_nested ? 1 : 0; }
35              
36 789     789 0 16102 sub get_last_nested { return $_[0]->nested->[ $_[0]->count_nested - 1 ]; }
37              
38             sub clear_last_nested {
39 81     81 0 1172 return delete $_[0]->nested->[ $_[0]->count_nested - 1 ];
40             }
41              
42 0     0 1 0 sub all_current_tables { return @{ $_[0]->current_tables }; }
  0         0  
43              
44 0     0 1 0 sub count_current_tables { return scalar @{ $_[0]->current_tables }; }
  0         0  
45              
46             sub current_or_nested {
47 7433 100   7433 0 14435 return $_[0]->has_nested ? $_[0]->get_last_nested : $_[0]->current_table;
48             }
49              
50             sub parse {
51 435     435 1 12846 my ( $self, $data ) = @_;
52              
53 435         4463 $self->SUPER::parse($data);
54              
55 435         7345 return $self->current_tables;
56             }
57              
58             sub parse_file {
59 61     61 1 566 my ( $self, $file ) = @_;
60              
61 61         264 $self->SUPER::parse_file($file);
62              
63 61         1315 return $self->current_tables;
64             }
65              
66             sub start {
67 6659     6659 1 16014 my ( $self, $tag, $attr, $attrseq, $origtext ) = @_;
68              
69 6659 100 100     24842 if ($self->current_element && $attr->{href}) {
70 262         378 push @{ $self->current_element->links }, $attr->{href};
  262         860  
71             }
72              
73 6659         12139 $tag = lc $tag;
74 6659 100       112769 if ( my $option = $self->options->{$tag} ) {
75 3721         29968 my $table = $self->current_or_nested;
76 3721         26657 my $action = $option->{add};
77 3721         9399 my $element = $self->$action($attr, $table);
78 3721         29120 return $self->current_element($element);
79             }
80              
81 2938 100       22996 if ( $self->has_caption_selector ) {
82 2352         15242 foreach my $selector ( @{ $self->caption_selectors }) {
  2352         35435  
83 3069 100       15765 if ( $selector eq $tag ) {
84 38         226 return $self->selected($attr);
85             }
86            
87 3031         4675 for my $field (qw/id class/) {
88 6060         9259 my $val = $attr->{$field};
89 6060 100       11187 next unless $val;
90            
91 1893 100       8642 if ( $val =~ m/$selector/ixms) {
92 2         19 return $self->selected($attr);
93             }
94             }
95             }
96             }
97              
98 2898         18965 return;
99             }
100              
101             sub text {
102 8204     8204 1 21965 my ( $self, $text ) = @_;
103              
104 8204 100       20426 if ( my $elem = $self->current_element ) {
105 6418 100       18641 if ( $text =~ m{\S+}xms ) {
106 2728         10418 $text =~ s{^\s+|\s+$}{}g;
107 2728         4029 push @{ $elem->data }, $text;
  2728         7633  
108             }
109             }
110 8204 100       18984 if ( my $selected = $self->selected) {
111 370 100       1129 if ( $text =~ m{\S+}xms ) {
112 317         588 $selected->{text} = $text;
113 317         588 $self->selected($selected);
114             }
115             }
116              
117 8204         40925 return;
118             }
119              
120             sub end {
121 6526     6526 1 14067 my ( $self, $tag, $origtext ) = @_;
122              
123 6526         10546 $tag = lc $tag;
124              
125 6526 100       106416 if ( my $option = $self->options->{$tag} ) {
126 3712         29778 my $table = $self->current_or_nested;
127 3712 100       30096 if ( my $action = $option->{close} ) {
128 1352         3759 my $element = $self->$action($table);
129             }
130             }
131              
132 6526         48463 return;
133             }
134              
135             sub _build_options {
136             return {
137 122     122   2276 table => {
138             add => '_add_table',
139             close => '_close_table',
140             },
141             th => {
142             add => '_add_header',
143             },
144             tr => {
145             add => '_add_row',
146             close => '_close_row',
147             },
148             td => {
149             add => '_add_cell',
150             },
151             caption => {
152             add => '_add_caption'
153             }
154             };
155             }
156              
157             sub _add_header {
158 547     547   1176 my ($self, $attr, $table) = @_;
159              
160 547         1522 my $header = $table->add_header($attr);
161 547         1522 $table->get_last_row->header($header);
162 547         3991 return $header;
163             }
164              
165             sub _add_row {
166 1062     1062   2208 my ($self, $attr, $table) = @_;
167              
168 1062         2737 my $row = $table->add_row($attr);
169 1062         2022 return $row;
170             }
171              
172             sub _add_cell {
173 1816     1816   3589 my ($self, $attr, $table) = @_;
174              
175 1816         4530 my $cell = $table->get_last_row->add_cell($attr);
176 1816         6483 $table->parse_to_column($cell);
177 1816         3488 return $cell;
178             }
179              
180             sub _add_caption {
181 0     0   0 my ($self, $attr, $table) = @_;
182              
183 0         0 my $caption = $table->add_caption($attr);
184 0         0 return $caption;
185             }
186              
187             sub _add_table {
188 296     296   679 my ($self, $attr, $table) = @_;
189              
190 296         5190 my $element = HTML::TableContent::Table->new($attr);
191              
192 296 100 66     3322 if ( defined $table && $table->isa('HTML::TableContent::Table') ) {
193 81 100       191 if ( $self->has_nested ) {
194 28         213 push @{ $self->current_table->nested }, $element;
  28         94  
195             }
196 81         468 push @{ $self->nested }, $element;
  81         1234  
197 81         461 push @{ $table->nested }, $element;
  81         188  
198 81         118 push @{ $table->get_last_row->get_last_cell->nested }, $element;
  81         237  
199             }
200             else {
201 215 100       787 if ( my $caption = $self->selected ){
202 18         83 $element->add_caption($caption);
203 18         337 $self->clear_selected;
204             }
205 215         762 $self->current_table($element);
206             }
207             }
208              
209             sub _close_table {
210 295     295   669 my ($self, $table) = @_;
211              
212 295 100       587 if ( $self->has_nested ) {
213 81         571 return $self->clear_last_nested;
214             }
215             else {
216 214         1411 push @{ $self->current_tables }, $self->current_table;
  214         3375  
217 214         4272 $self->clear_current_element;
218 214         4173 return $self->clear_current_table;
219             }
220             }
221              
222             sub _close_row {
223 1057     1057   2024 my ($self, $table) = @_;
224              
225 1057         2584 my $row = $table->get_last_row;
226              
227 1057 100       8164 if ( $row->header ) {
    100          
228 247         822 $table->clear_last_row;
229              
230 247         1676 my $index = 0;
231 247         779 foreach my $cell ( $row->all_cells ) {
232 39         780 my $row = $table->rows->[$index];
233 39 100       251 if ( defined $row ) {
234 26         43 push @{ $row->cells }, $cell;
  26         405  
235             }
236             else {
237 13         41 my $new_row = $table->add_row({});
238 13         31 push @{ $new_row->cells }, $cell;
  13         202  
239             }
240 39         199 $index++;
241             }
242             }
243             elsif ( $row->cell_count == 0 ) {
244 10         30 $table->clear_last_row;
245             }
246              
247 1057         7140 return;
248             }
249              
250             1;
251              
252             __END__