| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
6
|
|
|
6
|
|
241998
|
use strict; |
|
|
6
|
|
|
|
|
16
|
|
|
|
6
|
|
|
|
|
454
|
|
|
2
|
|
|
|
|
|
|
local $^W = 1; |
|
3
|
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package HTML::Element::Tiny; |
|
5
|
|
|
|
|
|
|
|
|
6
|
6
|
|
|
6
|
|
37
|
use vars qw($VERSION %HAS @TAGS %DEFAULT_CLOSED %DEFAULT_NEWLINE %TAG_CLASS); |
|
|
6
|
|
|
|
|
10
|
|
|
|
6
|
|
|
|
|
747
|
|
|
7
|
|
|
|
|
|
|
$VERSION = '0.006'; |
|
8
|
6
|
|
|
6
|
|
214
|
use 5.004; |
|
|
6
|
|
|
|
|
34
|
|
|
|
6
|
|
|
|
|
695
|
|
|
9
|
|
|
|
|
|
|
BEGIN { |
|
10
|
|
|
|
|
|
|
# @TAGS = |
|
11
|
|
|
|
|
|
|
# qw( a abbr acronym address area b base bdo big blockquote body br |
|
12
|
|
|
|
|
|
|
# button caption cite code col colgroup dd del div dfn dl dt em |
|
13
|
|
|
|
|
|
|
# fieldset form frame frameset h1 h2 h3 h4 h5 h6 head hr html i |
|
14
|
|
|
|
|
|
|
# iframe img input ins kbd label legend li link map meta noframes |
|
15
|
|
|
|
|
|
|
# noscript object ol optgroup option p param pre q samp script select |
|
16
|
|
|
|
|
|
|
# small span strong style sub sup table tbody td textarea tfoot th |
|
17
|
|
|
|
|
|
|
# thead title tr tt ul var ); |
|
18
|
6
|
|
|
6
|
|
17
|
%DEFAULT_CLOSED = map { $_ => 1 } |
|
|
66
|
|
|
|
|
159
|
|
|
19
|
|
|
|
|
|
|
qw( area base br col frame hr img input meta param link ); |
|
20
|
6
|
|
|
|
|
22
|
%DEFAULT_NEWLINE = map { $_ => 1 } |
|
|
42
|
|
|
|
|
206
|
|
|
21
|
|
|
|
|
|
|
qw( html head body div p tr table ); |
|
22
|
6
|
|
|
6
|
|
31
|
use vars qw(%_modver); |
|
|
6
|
|
|
|
|
24
|
|
|
|
6
|
|
|
|
|
891
|
|
|
23
|
6
|
|
|
|
|
24
|
%_modver = ( |
|
24
|
|
|
|
|
|
|
Clone => '0.28', |
|
25
|
|
|
|
|
|
|
); |
|
26
|
6
|
|
|
|
|
16
|
for my $module (qw(HTML::Entities Clone)) { |
|
27
|
12
|
|
100
|
|
|
87
|
my $modver = $_modver{$module} || 0; |
|
28
|
12
|
50
|
|
6
|
|
1062
|
$HAS{$module} = eval "use $module $modver (); 1" |
|
|
6
|
|
|
6
|
|
6896
|
|
|
|
6
|
|
|
|
|
43969
|
|
|
|
6
|
|
|
|
|
117
|
|
|
|
6
|
|
|
|
|
2799
|
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
29
|
|
|
|
|
|
|
unless defined $HAS{$module}; |
|
30
|
|
|
|
|
|
|
} |
|
31
|
|
|
|
|
|
|
} |
|
32
|
|
|
|
|
|
|
|
|
33
|
6
|
|
|
6
|
|
39
|
use Scalar::Util (); |
|
|
6
|
|
|
|
|
10
|
|
|
|
6
|
|
|
|
|
138
|
|
|
34
|
6
|
|
|
6
|
|
101
|
use Carp (); |
|
|
6
|
|
|
|
|
12
|
|
|
|
6
|
|
|
|
|
1228
|
|
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
#use overload ( |
|
37
|
|
|
|
|
|
|
# q{""} => 'as_string', |
|
38
|
|
|
|
|
|
|
# q{0+} => sub { Scalar::Util::refaddr($_[0]) }, |
|
39
|
|
|
|
|
|
|
# fallback => 1, |
|
40
|
|
|
|
|
|
|
#); |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
sub TAG () { 0 } |
|
43
|
|
|
|
|
|
|
sub ID () { 1 } |
|
44
|
|
|
|
|
|
|
sub CLASS () { 2 } |
|
45
|
|
|
|
|
|
|
sub ATTR () { 3 } |
|
46
|
|
|
|
|
|
|
sub CHILDREN () { 4 } |
|
47
|
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
%TAG_CLASS = ( |
|
49
|
|
|
|
|
|
|
-text => "-Text", |
|
50
|
|
|
|
|
|
|
-base => 'HTML::Element::Tiny', |
|
51
|
|
|
|
|
|
|
-default => 'HTML::Element::Tiny', |
|
52
|
|
|
|
|
|
|
); |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
sub _tag_class { |
|
55
|
498
|
|
|
498
|
|
727
|
my ($class, $tag) = @_; |
|
56
|
498
|
|
|
|
|
667
|
my $tag_lookup; |
|
57
|
|
|
|
|
|
|
{ |
|
58
|
6
|
|
|
6
|
|
34
|
no strict 'refs'; |
|
|
6
|
|
|
|
|
11
|
|
|
|
6
|
|
|
|
|
13679
|
|
|
|
498
|
|
|
|
|
692
|
|
|
59
|
498
|
50
|
50
|
|
|
516
|
if (exists ${$class . '::'}{TAG_CLASS} |
|
|
498
|
|
|
|
|
2157
|
|
|
|
498
|
|
|
|
|
2740
|
|
|
60
|
498
|
|
|
|
|
598
|
and *{${$class . '::'}{TAG_CLASS}}{HASH}) { |
|
61
|
498
|
|
|
|
|
576
|
$tag_lookup = \%{$class . '::TAG_CLASS'}; |
|
|
498
|
|
|
|
|
1397
|
|
|
62
|
|
|
|
|
|
|
# XXX should this really be the case? it seems like a very sane default. |
|
63
|
498
|
|
66
|
|
|
1378
|
$tag_lookup->{-base} ||= $class; |
|
64
|
498
|
|
66
|
|
|
1330
|
$tag_lookup->{-default} ||= $class; |
|
65
|
|
|
|
|
|
|
} else { |
|
66
|
0
|
|
|
|
|
0
|
$tag_lookup = {}; |
|
67
|
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
} |
|
69
|
498
|
|
|
|
|
769
|
my $tag_class; |
|
70
|
498
|
|
|
|
|
920
|
for my $href ($tag_lookup, \%TAG_CLASS) { |
|
71
|
785
|
100
|
|
|
|
2061
|
if ($tag_class = $href->{$tag}) { |
|
72
|
212
|
|
|
|
|
1377
|
$tag_class =~ s/^-/$href->{-base}::/; |
|
73
|
212
|
|
|
|
|
370
|
last; |
|
74
|
|
|
|
|
|
|
} |
|
75
|
|
|
|
|
|
|
} |
|
76
|
498
|
|
33
|
|
|
1848
|
$tag_class ||= $tag_lookup->{-default} || $TAG_CLASS{-default}; |
|
|
|
|
66
|
|
|
|
|
|
77
|
|
|
|
|
|
|
|
|
78
|
498
|
|
|
|
|
2140
|
return $tag_class; |
|
79
|
|
|
|
|
|
|
} |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
sub new { |
|
82
|
498
|
|
|
498
|
1
|
5432
|
my ($class, $arg, $extra) = @_; |
|
83
|
498
|
100
|
|
|
|
1116
|
unless (ref $arg) { |
|
84
|
211
|
|
|
|
|
400
|
return bless \$arg => _tag_class($class, '-text'); |
|
85
|
|
|
|
|
|
|
} |
|
86
|
287
|
50
|
|
|
|
562
|
Carp::confess "no tag: @$arg" unless @$arg; |
|
87
|
287
|
|
|
|
|
459
|
my $tag = shift @$arg; |
|
88
|
287
|
100
|
|
|
|
804
|
my $attr = ref $arg->[0] eq 'HASH' ? shift @$arg : {}; |
|
89
|
287
|
100
|
|
|
|
970
|
@{$attr}{keys %$extra} = (values %$extra) if $extra; |
|
|
272
|
|
|
|
|
696
|
|
|
90
|
287
|
|
100
|
|
|
2232
|
my $self = bless [ |
|
91
|
|
|
|
|
|
|
$tag, |
|
92
|
|
|
|
|
|
|
delete $attr->{id}, |
|
93
|
|
|
|
|
|
|
[ split /\s+/, delete $attr->{class} || '' ], |
|
94
|
|
|
|
|
|
|
$attr, |
|
95
|
|
|
|
|
|
|
[ ], |
|
96
|
|
|
|
|
|
|
] => _tag_class($class, $tag); |
|
97
|
287
|
100
|
|
|
|
1394
|
Scalar::Util::weaken($self->[ATTR]->{-parent}) |
|
98
|
|
|
|
|
|
|
if $self->[ATTR]->{-parent}; |
|
99
|
287
|
|
|
|
|
457
|
@{$self->[CHILDREN]} = map { $class->new($_, { -parent => $self }) } @$arg; |
|
|
287
|
|
|
|
|
665
|
|
|
|
479
|
|
|
|
|
1996
|
|
|
100
|
287
|
|
|
|
|
863
|
return $self; |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
|
|
103
|
872
|
|
|
872
|
1
|
5043
|
sub children { @{$_[0]->[CHILDREN]} } |
|
|
872
|
|
|
|
|
2679
|
|
|
104
|
3078
|
|
|
3078
|
1
|
163060
|
sub parent { $_[0]->[ATTR]->{-parent} } |
|
105
|
575
|
|
|
575
|
1
|
3380
|
sub tag { $_[0]->[TAG] } |
|
106
|
37
|
|
|
37
|
1
|
324
|
sub id { $_[0]->[ID] } |
|
107
|
13
|
|
|
13
|
1
|
16
|
sub class { join " ", @{$_[0]->[CLASS]} } |
|
|
13
|
|
|
|
|
58
|
|
|
108
|
275
|
|
|
275
|
1
|
306
|
sub classes { @{$_[0]->[CLASS]} } |
|
|
275
|
|
|
|
|
787
|
|
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
# _match needs to use accessors despite being internal because it may touch |
|
111
|
|
|
|
|
|
|
# non-arrayref subclasses like -Text |
|
112
|
|
|
|
|
|
|
sub _match { |
|
113
|
638
|
|
|
638
|
|
790
|
my ($self, $spec) = @_; |
|
114
|
|
|
|
|
|
|
return ( |
|
115
|
|
|
|
|
|
|
(defined $spec->{id} ? $spec->{id} eq ($self->id || '') : 1) && |
|
116
|
|
|
|
|
|
|
($spec->{-tag} ? $spec->{-tag} eq ($self->tag) : 1) && |
|
117
|
|
|
|
|
|
|
($spec->{class} ? ( |
|
118
|
|
|
|
|
|
|
# 'there are no parts of $spec->{class} that do not have a matching |
|
119
|
|
|
|
|
|
|
# entry in $self->classes' -- easier than saying all/all |
|
120
|
|
|
|
|
|
|
! grep { |
|
121
|
|
|
|
|
|
|
my $c = $_; |
|
122
|
|
|
|
|
|
|
! grep { $_ eq $c } $self->classes |
|
123
|
|
|
|
|
|
|
} split /\s+/, $spec->{class} |
|
124
|
|
|
|
|
|
|
) : 1) && |
|
125
|
|
|
|
|
|
|
(! grep { |
|
126
|
638
|
|
66
|
|
|
3241
|
$_ ne 'id' and $_ ne '-tag' and $_ ne 'class' and |
|
127
|
|
|
|
|
|
|
$spec->{$_} ne ($self->attr($_) || '') |
|
128
|
|
|
|
|
|
|
} keys %$spec) |
|
129
|
|
|
|
|
|
|
); |
|
130
|
|
|
|
|
|
|
} |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
sub _spec_to_str { |
|
133
|
0
|
|
|
0
|
|
0
|
my $spec = shift; |
|
134
|
0
|
|
|
|
|
0
|
return join " ", map { "$_=$spec->{$_}" } sort keys %$spec; |
|
|
0
|
|
|
|
|
0
|
|
|
135
|
|
|
|
|
|
|
} |
|
136
|
|
|
|
|
|
|
|
|
137
|
15
|
|
|
15
|
|
71
|
sub _iter (&) { bless $_[0] => 'HTML::Element::Tiny::Iterator' } |
|
138
|
9
|
|
|
9
|
|
64
|
sub _coll (@) { HTML::Element::Tiny::Collection->new(@_) } |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
sub find_iter { |
|
141
|
7
|
|
|
7
|
1
|
14
|
my ($self, $spec) = @_; |
|
142
|
7
|
|
|
|
|
22
|
my $iter = $self->iter; |
|
143
|
|
|
|
|
|
|
return _iter { |
|
144
|
|
|
|
|
|
|
{ |
|
145
|
19
|
100
|
|
19
|
|
23
|
return unless defined(my $next = $iter->next); |
|
|
87
|
|
|
|
|
178
|
|
|
146
|
80
|
100
|
|
|
|
345
|
redo unless $next->_match($spec); |
|
147
|
12
|
|
|
|
|
36
|
return $next; |
|
148
|
|
|
|
|
|
|
} |
|
149
|
7
|
|
|
|
|
41
|
}; |
|
150
|
|
|
|
|
|
|
} |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
sub find { |
|
153
|
5
|
|
|
5
|
1
|
14
|
my ($self, $spec) = @_; |
|
154
|
|
|
|
|
|
|
# id should short-circuit |
|
155
|
5
|
50
|
|
|
|
17
|
return grep( { defined && length } $spec->{id} ) |
|
|
5
|
50
|
|
|
|
43
|
|
|
156
|
|
|
|
|
|
|
? _coll($self->find_iter($spec)->next) |
|
157
|
|
|
|
|
|
|
: $self->all->filter($spec); |
|
158
|
|
|
|
|
|
|
} |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
sub find_one { |
|
161
|
6
|
|
|
6
|
1
|
1292
|
my ($self, $spec) = @_; |
|
162
|
6
|
|
|
|
|
21
|
my $iter = $self->find_iter($spec); |
|
163
|
6
|
|
|
|
|
28
|
my $elem = $iter->next; |
|
164
|
6
|
50
|
|
|
|
20
|
unless ($elem) { |
|
165
|
0
|
|
|
|
|
0
|
Carp::croak "no element found for " . _spec_to_str($spec); |
|
166
|
|
|
|
|
|
|
} |
|
167
|
6
|
50
|
|
|
|
23
|
if (my $next = $iter->next) { |
|
168
|
0
|
|
|
|
|
0
|
Carp::croak "not exactly one element: found $elem, $next"; |
|
169
|
|
|
|
|
|
|
} |
|
170
|
6
|
|
|
|
|
68
|
return $elem; |
|
171
|
|
|
|
|
|
|
} |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
sub all { |
|
174
|
7
|
|
|
7
|
1
|
41
|
return _coll($_[0]->_all); |
|
175
|
|
|
|
|
|
|
} |
|
176
|
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
sub _all { |
|
178
|
300
|
|
|
300
|
|
334
|
my $self = shift; |
|
179
|
300
|
|
|
|
|
482
|
return $self, map({ $_->_all } $self->children ); |
|
|
515
|
|
|
|
|
948
|
|
|
180
|
|
|
|
|
|
|
} |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
sub iter { |
|
183
|
8
|
|
|
8
|
1
|
24
|
my $self = shift; |
|
184
|
8
|
|
|
|
|
17
|
my @queue = $self; |
|
185
|
|
|
|
|
|
|
return _iter { |
|
186
|
103
|
100
|
|
103
|
|
239
|
return unless @queue; |
|
187
|
95
|
|
|
|
|
124
|
my $next = shift @queue; |
|
188
|
95
|
|
|
|
|
200
|
unshift @queue, $next->children; |
|
189
|
95
|
|
|
|
|
274
|
return $next; |
|
190
|
8
|
|
|
|
|
50
|
}; |
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
sub attr { |
|
194
|
47
|
|
|
47
|
1
|
1980
|
my ($self, $arg) = @_; |
|
195
|
47
|
100
|
|
|
|
143
|
if (ref $arg eq 'HASH') { |
|
|
|
50
|
|
|
|
|
|
|
196
|
12
|
|
|
|
|
50
|
while (my ($k, $v) = each %$arg) { |
|
197
|
12
|
100
|
|
|
|
56
|
if ($k eq 'id') { $self->[ID] = $v } |
|
|
5
|
100
|
|
|
|
16
|
|
|
198
|
1
|
|
|
|
|
4
|
elsif ($k eq 'class') { @{$self->[CLASS]} = split /\s+/, $v; } |
|
|
1
|
|
|
|
|
7
|
|
|
199
|
6
|
|
|
|
|
30
|
else { $self->[ATTR]->{$k} = $v; } |
|
200
|
|
|
|
|
|
|
} |
|
201
|
12
|
|
|
|
|
34
|
return $self; |
|
202
|
|
|
|
|
|
|
} elsif (not ref $arg) { |
|
203
|
35
|
100
|
|
|
|
98
|
return $self->[ID] if $arg eq 'id'; |
|
204
|
19
|
100
|
|
|
|
63
|
return $self->class if $arg eq 'class'; |
|
205
|
6
|
|
|
|
|
29
|
return $self->[ATTR]->{$arg}; |
|
206
|
|
|
|
|
|
|
} |
|
207
|
0
|
|
|
|
|
0
|
Carp::croak "invalid argument to attr(): '$arg' (must be hashref or scalar)"; |
|
208
|
|
|
|
|
|
|
} |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
sub _Clone_clone { |
|
211
|
0
|
|
|
0
|
|
0
|
my ($self, $extra) = @_; |
|
212
|
0
|
|
|
|
|
0
|
my $clone = Clone::clone($self); |
|
213
|
0
|
|
|
|
|
0
|
delete $clone->[ATTR]->{-parent}; |
|
214
|
0
|
0
|
0
|
|
|
0
|
$clone->attr($extra) if $extra and %$extra; |
|
215
|
0
|
|
|
|
|
0
|
return $clone; |
|
216
|
|
|
|
|
|
|
} |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
sub _my_clone { |
|
219
|
251
|
|
|
251
|
|
414
|
my ($self, $extra) = @_; |
|
220
|
251
|
|
|
|
|
294
|
my %attr = %{$self->[ATTR]}; |
|
|
251
|
|
|
|
|
851
|
|
|
221
|
251
|
|
|
|
|
701
|
delete $attr{-parent}; |
|
222
|
251
|
100
|
|
|
|
1809
|
my $clone = bless [ |
|
223
|
|
|
|
|
|
|
$self->[TAG], |
|
224
|
|
|
|
|
|
|
$self->[ID], |
|
225
|
|
|
|
|
|
|
[ $self->classes ], |
|
226
|
251
|
|
|
|
|
592
|
{ %attr, %{$extra || {}} }, |
|
227
|
|
|
|
|
|
|
[], |
|
228
|
|
|
|
|
|
|
] => ref $self; |
|
229
|
251
|
|
|
|
|
585
|
$clone->append($self->children); |
|
230
|
251
|
|
|
|
|
577
|
return $clone; |
|
231
|
|
|
|
|
|
|
} |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
my $clone_type = sprintf "_%s_clone", (grep { $HAS{$_} } qw(Clone))[0] || 'my'; |
|
234
|
|
|
|
|
|
|
sub clone { |
|
235
|
250
|
|
|
250
|
1
|
351
|
my ($self, $extra) = @_; |
|
236
|
6
|
|
|
6
|
|
98
|
my $clone = do { no strict 'refs'; &$clone_type($self, $extra) }; |
|
|
6
|
|
|
|
|
13
|
|
|
|
6
|
|
|
|
|
6006
|
|
|
|
250
|
|
|
|
|
280
|
|
|
|
250
|
|
|
|
|
593
|
|
|
237
|
|
|
|
|
|
|
|
|
238
|
250
|
50
|
|
|
|
1123
|
Scalar::Util::weaken($clone->[ATTR]->{-parent}) |
|
239
|
|
|
|
|
|
|
if $clone->[ATTR]->{-parent}; |
|
240
|
250
|
|
|
|
|
833
|
return $clone; |
|
241
|
|
|
|
|
|
|
} |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
sub _new_children { |
|
244
|
254
|
|
|
254
|
|
303
|
my $self = shift; |
|
245
|
439
|
100
|
|
|
|
1701
|
return map { |
|
|
|
100
|
|
|
|
|
|
|
246
|
254
|
|
|
|
|
364
|
Scalar::Util::blessed($_) |
|
247
|
|
|
|
|
|
|
? $_->parent |
|
248
|
|
|
|
|
|
|
? $_->clone({ -parent => $self }) |
|
249
|
|
|
|
|
|
|
: $_->attr({ -parent => $self }) |
|
250
|
|
|
|
|
|
|
: ref($self)->new($_, { -parent => $self }) |
|
251
|
|
|
|
|
|
|
} @_; |
|
252
|
|
|
|
|
|
|
} |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
sub prepend { |
|
255
|
1
|
|
|
1
|
1
|
2
|
my $self = shift; |
|
256
|
1
|
|
|
|
|
1
|
unshift @{ $self->[CHILDREN] }, $self->_new_children(@_); |
|
|
1
|
|
|
|
|
4
|
|
|
257
|
|
|
|
|
|
|
} |
|
258
|
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
sub append { |
|
260
|
253
|
|
|
253
|
1
|
304
|
my $self = shift; |
|
261
|
253
|
|
|
|
|
271
|
push @{ $self->[CHILDREN] }, $self->_new_children(@_); |
|
|
253
|
|
|
|
|
632
|
|
|
262
|
|
|
|
|
|
|
} |
|
263
|
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
sub remove_child { |
|
265
|
2
|
|
|
2
|
1
|
4
|
my $self = shift; |
|
266
|
2
|
|
|
|
|
3
|
my (%idx, %obj); |
|
267
|
2
|
|
|
|
|
5
|
for (@_) { |
|
268
|
4
|
100
|
|
|
|
15
|
if (Scalar::Util::blessed($_)) { |
|
269
|
3
|
|
|
|
|
14
|
$obj{Scalar::Util::refaddr($_)}++; |
|
270
|
|
|
|
|
|
|
} else { |
|
271
|
1
|
|
|
|
|
4
|
$idx{$_}++; |
|
272
|
|
|
|
|
|
|
} |
|
273
|
|
|
|
|
|
|
} |
|
274
|
2
|
|
|
|
|
5
|
my @children; |
|
275
|
|
|
|
|
|
|
my @removed; |
|
276
|
2
|
|
|
|
|
3
|
for my $i (0..$#{$self->[CHILDREN]}) { |
|
|
2
|
|
|
|
|
7
|
|
|
277
|
5
|
|
|
|
|
8
|
my $child = $self->[CHILDREN]->[$i]; |
|
278
|
5
|
100
|
100
|
|
|
29
|
if ($idx{$i} or $obj{Scalar::Util::refaddr($child)}) { |
|
279
|
4
|
|
|
|
|
14
|
$child->attr({ -parent => undef }); |
|
280
|
4
|
|
|
|
|
11
|
push @removed, $child; |
|
281
|
|
|
|
|
|
|
} else { |
|
282
|
1
|
|
|
|
|
3
|
push @children, $child; |
|
283
|
|
|
|
|
|
|
} |
|
284
|
|
|
|
|
|
|
} |
|
285
|
2
|
|
|
|
|
5
|
$self->[CHILDREN] = \@children; |
|
286
|
2
|
|
|
|
|
56
|
return _coll(@removed); |
|
287
|
|
|
|
|
|
|
} |
|
288
|
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
sub as_HTML { |
|
290
|
10
|
|
|
10
|
1
|
19
|
my ($self, $arg) = @_; |
|
291
|
10
|
|
50
|
|
|
43
|
$arg ||= {}; |
|
292
|
10
|
|
|
|
|
27
|
my $str = "<$self->[TAG]"; |
|
293
|
10
|
|
|
|
|
13
|
for ( sort grep { !/^-/ } keys %{$self->[ATTR]}, qw(id class) ) { |
|
|
22
|
|
|
|
|
81
|
|
|
|
10
|
|
|
|
|
32
|
|
|
294
|
21
|
|
|
|
|
50
|
my $val = $self->attr($_); |
|
295
|
21
|
100
|
100
|
|
|
123
|
$str .= qq{ $_="} . $self->attr($_) . qq{"} |
|
|
|
|
66
|
|
|
|
|
|
296
|
|
|
|
|
|
|
if defined $val and ($_ ne 'class' or length($val)); |
|
297
|
|
|
|
|
|
|
} |
|
298
|
|
|
|
|
|
|
# $str .= qq{ id="$self->[ID]"} if $self->[ID]; |
|
299
|
|
|
|
|
|
|
# $str .= qq{ class="} . $self->class . qq{"} if @{$self->classes}; |
|
300
|
|
|
|
|
|
|
# $str .= qq{ $_="$self->[ATTR]->{$_}"} |
|
301
|
|
|
|
|
|
|
# for sort grep { !/^-/ } keys %{$self->[ATTR]}; |
|
302
|
10
|
100
|
|
|
|
33
|
if ($DEFAULT_CLOSED{$self->[TAG]}) { |
|
303
|
2
|
|
|
|
|
5
|
$str .= ' />'; |
|
304
|
|
|
|
|
|
|
} else { |
|
305
|
8
|
|
|
|
|
27
|
$str .= '>' . join("", map { $_->as_HTML } $self->children); |
|
|
5
|
|
|
|
|
21
|
|
|
306
|
8
|
|
|
|
|
719
|
$str .= "$self->[TAG]>"; |
|
307
|
|
|
|
|
|
|
} |
|
308
|
10
|
50
|
|
|
|
27
|
$str .= "\n" if $DEFAULT_NEWLINE{$self->[TAG]}; |
|
309
|
10
|
|
|
|
|
60
|
return $str; |
|
310
|
|
|
|
|
|
|
} |
|
311
|
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
#sub as_string { |
|
313
|
|
|
|
|
|
|
# my ($self) = @_; |
|
314
|
|
|
|
|
|
|
# my $str = $self->tag; |
|
315
|
|
|
|
|
|
|
# $str .= qq{ id="} . $self->id . q{"} if $self->id; |
|
316
|
|
|
|
|
|
|
# $str .= qq{ class="} . $self->class . q{"} if $self->classes; |
|
317
|
|
|
|
|
|
|
# return "<$str>"; |
|
318
|
|
|
|
|
|
|
#} |
|
319
|
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
package HTML::Element::Tiny::Text; |
|
321
|
|
|
|
|
|
|
|
|
322
|
6
|
|
|
6
|
|
44
|
BEGIN { use vars qw(@ISA); @ISA = 'HTML::Element::Tiny' } |
|
|
6
|
|
|
6
|
|
10
|
|
|
|
6
|
|
|
|
|
353
|
|
|
|
6
|
|
|
|
|
4772
|
|
|
323
|
|
|
|
|
|
|
|
|
324
|
38
|
|
|
38
|
|
56
|
sub children { return () } |
|
325
|
222
|
|
|
222
|
|
738
|
sub _all { return $_[0] } |
|
326
|
430
|
|
|
430
|
|
4110
|
sub tag { '-text' } |
|
327
|
187
|
|
|
187
|
|
783
|
sub parent { return () } |
|
328
|
4
|
|
|
4
|
|
28
|
sub id { return } |
|
329
|
0
|
|
|
0
|
|
0
|
sub class { return } |
|
330
|
16
|
|
|
16
|
|
78
|
sub classes { return () } |
|
331
|
187
|
50
|
|
187
|
|
951
|
sub attr { return ref $_[1] ? $_[0] : (); } |
|
332
|
0
|
|
|
0
|
|
0
|
sub clone { return $_[0] } |
|
333
|
0
|
|
|
0
|
|
0
|
sub append { die "unimplemented" } |
|
334
|
0
|
|
|
0
|
|
0
|
sub remove_child { die "unimplemented" } |
|
335
|
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
my %ENT_MAP = ( |
|
337
|
|
|
|
|
|
|
'&' => '&', |
|
338
|
|
|
|
|
|
|
'<' => '<', |
|
339
|
|
|
|
|
|
|
'>' => '>', |
|
340
|
|
|
|
|
|
|
'"' => '"', |
|
341
|
|
|
|
|
|
|
"'" => ''', |
|
342
|
|
|
|
|
|
|
); |
|
343
|
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
sub as_HTML { |
|
345
|
5
|
50
|
|
5
|
|
12
|
return HTML::Entities::encode_entities(${$_[0]}) |
|
|
0
|
|
|
|
|
0
|
|
|
346
|
|
|
|
|
|
|
if $HTML::Element::Tiny::HAS_HTML_ENTITIES; |
|
347
|
5
|
|
|
|
|
7
|
my $str = ${$_[0]}; |
|
|
5
|
|
|
|
|
15
|
|
|
348
|
5
|
|
|
|
|
13
|
$str =~ s/([<>&'"])/$ENT_MAP{$1}/eg; |
|
|
7
|
|
|
|
|
32
|
|
|
349
|
5
|
|
|
|
|
19
|
return $str; |
|
350
|
|
|
|
|
|
|
} |
|
351
|
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
package HTML::Element::Tiny::Iterator; |
|
353
|
|
|
|
|
|
|
|
|
354
|
122
|
|
|
122
|
|
326
|
sub next { $_[0]->() } |
|
355
|
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
package HTML::Element::Tiny::Collection; |
|
357
|
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
sub new { |
|
359
|
25
|
|
|
25
|
|
56
|
my $class = shift; |
|
360
|
25
|
|
66
|
|
|
277
|
my $self = bless [ @_ ] => ref $class || $class; |
|
361
|
25
|
100
|
|
|
|
195
|
return wantarray ? @$self : $self; |
|
362
|
|
|
|
|
|
|
} |
|
363
|
|
|
|
|
|
|
|
|
364
|
14
|
|
|
14
|
|
3459
|
sub size { scalar @{$_[0]} } |
|
|
14
|
|
|
|
|
78
|
|
|
365
|
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
sub each { |
|
367
|
1
|
|
|
1
|
|
2
|
my ($self, $code) = @_; |
|
368
|
1
|
|
|
|
|
4
|
for (@$self) { $code->() } |
|
|
5
|
|
|
|
|
13
|
|
|
369
|
1
|
|
|
|
|
3
|
return $self; |
|
370
|
|
|
|
|
|
|
} |
|
371
|
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
sub one { |
|
373
|
3
|
|
|
3
|
|
4
|
my $self = shift; |
|
374
|
3
|
100
|
|
|
|
299
|
Carp::croak "not exactly one element (@$self)" unless @$self == 1; |
|
375
|
1
|
|
|
|
|
3
|
return $self->[0]; |
|
376
|
|
|
|
|
|
|
} |
|
377
|
|
|
|
|
|
|
|
|
378
|
1
|
|
|
1
|
|
1053
|
sub all { @{$_[0]} } |
|
|
1
|
|
|
|
|
11
|
|
|
379
|
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
sub map { |
|
381
|
1
|
|
|
1
|
|
5
|
my ($self, $code) = @_; |
|
382
|
1
|
|
|
|
|
4
|
return map { $code->() } @$self; |
|
|
5
|
|
|
|
|
13
|
|
|
383
|
|
|
|
|
|
|
} |
|
384
|
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
sub filter { |
|
386
|
11
|
|
|
11
|
|
1221
|
my ($self, $spec) = @_; |
|
387
|
11
|
|
|
|
|
33
|
return $self->new(grep { $_->_match($spec) } @$self); |
|
|
102
|
|
|
|
|
287
|
|
|
388
|
|
|
|
|
|
|
} |
|
389
|
|
|
|
|
|
|
|
|
390
|
6
|
|
|
6
|
|
1242
|
BEGIN { *grep = \&filter } |
|
391
|
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
sub not { |
|
393
|
3
|
|
|
3
|
|
9
|
my ($self, $spec) = @_; |
|
394
|
3
|
|
|
|
|
26
|
return $self->new(grep { ! $_->_match($spec) } @$self); |
|
|
456
|
|
|
|
|
984
|
|
|
395
|
|
|
|
|
|
|
} |
|
396
|
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
sub attr { |
|
398
|
1
|
|
|
1
|
|
3
|
my ($self, $arg) = @_; |
|
399
|
|
|
|
|
|
|
return ref $arg |
|
400
|
5
|
|
|
5
|
|
11
|
? $self->each(sub { $_->attr($arg) }) |
|
401
|
0
|
0
|
|
0
|
|
|
: $self->map(sub { grep { defined && length } $_->attr($arg) }) |
|
|
0
|
|
|
|
|
|
|
|
402
|
1
|
50
|
|
|
|
10
|
; |
|
403
|
|
|
|
|
|
|
} |
|
404
|
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
1; |
|
406
|
|
|
|
|
|
|
__END__ |