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__ |