File Coverage

blib/lib/Mojo/DOM58.pm
Criterion Covered Total %
statement 234 234 100.0
branch 121 124 97.5
condition 53 60 88.3
subroutine 78 78 100.0
pod 43 44 97.7
total 529 540 97.9


line stmt bran cond sub pod time code
1             package Mojo::DOM58;
2              
3 2     2   132512 use strict;
  2         13  
  2         60  
4 2     2   10 use warnings;
  2         3  
  2         216  
5              
6             use overload
7 4     4   12 '@{}' => sub { shift->child_nodes },
8 93     93   227 '%{}' => sub { shift->attr },
9 32     32   2692 bool => sub {1},
10 129     129   13794 '""' => sub { shift->to_string },
11 2     2   2311 fallback => 1;
  2         1864  
  2         34  
12              
13 2     2   208 use Exporter 'import';
  2         5  
  2         63  
14 2     2   423 use Mojo::DOM58::_Collection;
  2         5  
  2         51  
15 2     2   838 use Mojo::DOM58::_CSS;
  2         6  
  2         70  
16 2     2   812 use Mojo::DOM58::_HTML 'tag_to_html';
  2         6  
  2         137  
17 2     2   14 use Scalar::Util qw(blessed weaken);
  2         4  
  2         95  
18 2     2   1364 use Storable 'dclone';
  2         6362  
  2         7579  
19              
20             our $VERSION = '2.000';
21              
22             our @EXPORT_OK = 'tag_to_html';
23              
24             sub new {
25 1995     1995 1 21946 my $class = shift;
26 1995   66     4520 my $self = bless \Mojo::DOM58::_HTML->new, ref $class || $class;
27 1995 100       5572 return @_ ? $self->parse(@_) : $self;
28             }
29              
30             sub new_tag {
31 11     11 1 22 my $self = shift;
32 11         21 my $new = $self->new;
33 11         35 $$new->tag(@_);
34 11 100       21 $$new->xml($$self->xml) if ref $self;
35 11         32 return $new;
36             }
37              
38 1     1 0 69 sub TO_JSON { ${shift()}->render }
  1         4  
39              
40 19     19 1 63 sub all_text { _text(_nodes(shift->tree), 1) }
41              
42 15     15 1 50 sub ancestors { _select($_[0]->_collect([_ancestors($_[0]->tree)]), $_[1]) }
43              
44 9     9 1 30 sub append { shift->_add(1, @_) }
45 13     13 1 39 sub append_content { shift->_content(1, 0, @_) }
46              
47             sub at {
48 536     536 1 1618 my $self = shift;
49 536 100       1250 return undef unless my $result = $self->_css->select_one(@_);
50 493         2543 return $self->_build($result, $self->xml);
51             }
52              
53             sub attr {
54 166     166 1 283 my $self = shift;
55              
56             # Hash
57 166         296 my $tree = $self->tree;
58 166 100       405 my $attrs = $tree->[0] ne 'tag' ? {} : $tree->[2];
59 166 100       859 return $attrs unless @_;
60              
61             # Get
62 40 100 100     297 return $attrs->{$_[0]} unless @_ > 1 || ref $_[0];
63              
64             # Set
65 4 100       16 my $values = ref $_[0] ? $_[0] : {@_};
66 4         16 @$attrs{keys %$values} = values %$values;
67              
68 4         17 return $self;
69             }
70              
71 59     59 1 169 sub child_nodes { $_[0]->_collect(_nodes($_[0]->tree)) }
72              
73 13     13 1 52 sub children { _select($_[0]->_collect(_nodes($_[0]->tree, 1)), $_[1]) }
74              
75             sub content {
76 55     55 1 96 my $self = shift;
77              
78 55         111 my $type = $self->type;
79 55 100 100     259 if ($type eq 'root' || $type eq 'tag') {
80 24 100       77 return $self->_content(0, 1, @_) if @_;
81 7         17 my $html = Mojo::DOM58::_HTML->new(xml => $self->xml);
82 7         15 return join '', map { $html->tree($_)->render } @{_nodes($self->tree)};
  12         28  
  7         15  
83             }
84              
85 31 100       75 return $self->tree->[1] unless @_;
86 3         7 $self->tree->[1] = shift;
87 3         12 return $self;
88             }
89              
90 13     13 1 32 sub descendant_nodes { $_[0]->_collect(_all(_nodes($_[0]->tree))) }
91              
92             sub find {
93 402     402 1 1648 my $self = shift;
94 402         1040 return $self->_collect($self->_css->select(@_));
95             }
96              
97 8     8 1 21 sub following { _select($_[0]->_collect(_siblings($_[0]->tree, 1, 1)), $_[1]) }
98 7     7 1 18 sub following_nodes { $_[0]->_collect(_siblings($_[0]->tree, 0, 1)) }
99              
100 44     44 1 114 sub matches { shift->_css->matches(@_) }
101              
102             sub namespace {
103 18     18 1 35 my $self = shift;
104              
105 18 100       35 return undef if (my $tree = $self->tree)->[0] ne 'tag';
106              
107             # Extract namespace prefix and search parents
108 16 100       77 my $ns = $tree->[1] =~ /^(.*?):/ ? "xmlns:$1" : undef;
109 16         35 for my $node ($tree, _ancestors($tree)) {
110              
111             # Namespace for prefix
112 35         50 my $attrs = $node->[2];
113 35 100 100     75 if ($ns) { $_ eq $ns and return $attrs->{$_} for keys %$attrs }
  13 100       67  
114              
115             # Namespace attribute
116 10         49 elsif (defined $attrs->{xmlns}) { return $attrs->{xmlns} }
117             }
118              
119 1         5 return undef;
120             }
121              
122 13     13 1 54 sub next { $_[0]->_maybe(_siblings($_[0]->tree, 1, 1, 0)) }
123 5     5 1 10 sub next_node { $_[0]->_maybe(_siblings($_[0]->tree, 0, 1, 0)) }
124              
125             sub parent {
126 48     48 1 87 my $self = shift;
127 48 50       88 return undef if (my $tree = $self->tree)->[0] eq 'root';
128 48         99 return $self->_build(_parent($tree), $self->xml);
129             }
130              
131 154 50   154 1 260 sub parse { ${$_[0]}->parse($_[1]) and return $_[0] }
  154         585  
132              
133 5     5 1 13 sub preceding { _select($_[0]->_collect(_siblings($_[0]->tree, 1, 0)), $_[1]) }
134 7     7 1 17 sub preceding_nodes { $_[0]->_collect(_siblings($_[0]->tree, 0)) }
135              
136 11     11 1 32 sub prepend { shift->_add(0, @_) }
137 6     6 1 16 sub prepend_content { shift->_content(0, 0, @_) }
138              
139 7     7 1 20 sub previous { $_[0]->_maybe(_siblings($_[0]->tree, 1, 0, -1)) }
140 5     5 1 11 sub previous_node { $_[0]->_maybe(_siblings($_[0]->tree, 0, 0, -1)) }
141              
142 6     6 1 17 sub remove { shift->replace('') }
143              
144             sub replace {
145 24     24 1 56 my ($self, $new) = @_;
146 24 100       55 return $self->parse($new) if (my $tree = $self->tree)->[0] eq 'root';
147 16         37 return $self->_replace(_parent($tree), $tree, _nodes($self->_parse($new)));
148             }
149              
150             sub root {
151 12     12 1 36 my $self = shift;
152 12 100       26 return $self unless my $tree = _ancestors($self->tree, 1);
153 9         23 return $self->_build($tree, $self->xml);
154             }
155              
156             sub selector {
157 13 100   13 1 24 return undef unless (my $tree = shift->tree)->[0] eq 'tag';
158             return join ' > ',
159 11         25 reverse map { $_->[1] . ':nth-child(' . (@{_siblings($_, 1)} + 1) . ')' }
  31         52  
  31         46  
160             $tree, _ancestors($tree);
161             }
162              
163             sub strip {
164 9     9 1 17 my $self = shift;
165 9 100       19 return $self if (my $tree = $self->tree)->[0] ne 'tag';
166 7         21 return $self->_replace($tree->[3], $tree, _nodes($tree));
167             }
168              
169             sub tag {
170 93     93 1 214 my ($self, $tag) = @_;
171 93 100       173 return undef if (my $tree = $self->tree)->[0] ne 'tag';
172 91 100       439 return $tree->[1] unless $tag;
173 1         3 $tree->[1] = $tag;
174 1         4 return $self;
175             }
176              
177 1     1 1 5 sub tap { Mojo::DOM58::_Collection::tap(@_) }
178              
179 652     652 1 1758 sub text { _text(_nodes(shift->tree), 0) }
180              
181 139     139 1 216 sub to_string { ${shift()}->render }
  139         480  
182              
183 4295 100 50 4295 1 8393 sub tree { @_ > 1 ? (${$_[0]}->tree($_[1]) and return $_[0]) : ${$_[0]}->tree }
  2459         7304  
184              
185 78     78 1 180 sub type { shift->tree->[0] }
186              
187             sub val {
188 27     27 1 38 my $self = shift;
189              
190             # "option"
191 27 100       57 return defined($self->{value}) ? $self->{value} : $self->text
    100          
192             if (my $tag = $self->tag) eq 'option';
193              
194             # "input" ("type=checkbox" and "type=radio")
195 17   100     45 my $type = $self->{type} || '';
196 17 100 100     74 return defined $self->{value} ? $self->{value} : 'on'
    100 100        
197             if $tag eq 'input' && ($type eq 'radio' || $type eq 'checkbox');
198              
199             # "textarea", "input" or "button"
200 12 100       36 return $tag eq 'textarea' ? $self->text : $self->{value} if $tag ne 'select';
    100          
201              
202             # "select"
203             my $v = $self->find('option:checked:not([disabled])')
204 5     6   15 ->grep(sub { !$_->ancestors('optgroup[disabled]')->size })->map('val');
  6         16  
205 5 100       31 return exists $self->{multiple} ? $v->size ? $v->to_array : undef : $v->last;
    100          
206             }
207              
208 1     1 1 1277 sub with_roles { Mojo::DOM58::_Collection::with_roles(@_) }
209              
210 9     9 1 31 sub wrap { shift->_wrap(0, @_) }
211 7     7 1 22 sub wrap_content { shift->_wrap(1, @_) }
212              
213 3036 100 50 3036 1 6111 sub xml { @_ > 1 ? (${$_[0]}->xml($_[1]) and return $_[0]) : ${$_[0]}->xml }
  1189         3945  
214              
215             sub _add {
216 20     20   41 my ($self, $offset, $new) = @_;
217              
218 20 100       39 return $self if (my $tree = $self->tree)->[0] eq 'root';
219              
220 16         38 my $parent = _parent($tree);
221             splice @$parent, _offset($parent, $tree) + $offset, 0,
222 16         30 @{_link($parent, _nodes($self->_parse($new)))};
  16         39  
223              
224 16         64 return $self;
225             }
226              
227             sub _all {
228 21     21   32 my $nodes = shift;
229 21 100       35 @$nodes = map { $_->[0] eq 'tag' ? ($_, @{_all(_nodes($_))}) : ($_) } @$nodes;
  60         156  
  8         15  
230 21         50 return $nodes;
231             }
232              
233             sub _ancestors {
234 54     54   113 my ($tree, $root) = @_;
235              
236 54 100       124 return () unless $tree = _parent($tree);
237 51         81 my @ancestors;
238 51   66     75 do { push @ancestors, $tree }
  137         458  
239             while ($tree->[0] eq 'tag') && ($tree = $tree->[3]);
240 51 100       208 return $root ? $ancestors[-1] : @ancestors[0 .. $#ancestors - 1];
241             }
242              
243 1836     1836   3770 sub _build { shift->new->tree(shift)->xml(shift) }
244              
245             sub _collect {
246 529   50 529   1557 my ($self, $nodes) = (shift, shift || []);
247 529         1101 my $xml = $self->xml;
248 529         1148 return Mojo::DOM58::_Collection->new(map { $self->_build($_, $xml) } @$nodes);
  1266         2332  
249             }
250              
251             sub _content {
252 36     36   81 my ($self, $start, $offset, $new) = @_;
253              
254 36         70 my $tree = $self->tree;
255 36 100 100     162 unless ($tree->[0] eq 'root' || $tree->[0] eq 'tag') {
256 2         6 my $old = $self->content;
257 2 100       10 return $self->content($start ? $old . $new : $new . $old);
258             }
259              
260 34 100       102 $start = $start ? ($#$tree + 1) : _start($tree);
261 34 100       72 $offset = $offset ? $#$tree : 0;
262 34         70 splice @$tree, $start, $offset, @{_link($tree, _nodes($self->_parse($new)))};
  34         81  
263              
264 34         142 return $self;
265             }
266              
267 982     982   2300 sub _css { Mojo::DOM58::_CSS->new(tree => shift->tree) }
268              
269 1     1   6 sub _fragment { _link(my $r = ['root', @_], [@_]); $r }
  1         2  
270              
271             sub _link {
272 98     98   204 my ($parent, $children) = @_;
273              
274             # Link parent to children
275 98         185 for my $node (@$children) {
276 102 100       200 my $offset = $node->[0] eq 'tag' ? 3 : 2;
277 102         173 $node->[$offset] = $parent;
278 102         249 weaken $node->[$offset];
279             }
280              
281 98         296 return $children;
282             }
283              
284 30 100   30   98 sub _maybe { $_[1] ? $_[0]->_build($_[1], $_[0]->xml) : undef }
285              
286             sub _nodes {
287 1096 50   1096   2429 return () unless my $tree = shift;
288 1096         2146 my @nodes = @$tree[_start($tree) .. $#$tree];
289 1096 100       3270 return shift() ? [grep { $_->[0] eq 'tag' } @nodes] : \@nodes;
  84         270  
290             }
291              
292             sub _offset {
293 46     46   80 my ($parent, $child) = @_;
294 46         75 my $i = _start($parent);
295 46 100       231 $_ eq $child ? last : $i++ for @$parent[$i .. $#$parent];
296 46         92 return $i;
297             }
298              
299 223 100   223   673 sub _parent { $_[0]->[$_[0][0] eq 'tag' ? 3 : 2] }
300              
301             sub _parse {
302 80     80   157 my ($self, $input) = @_;
303 80 100 66     375 return Mojo::DOM58::_HTML->new(xml => $self->xml)->parse($input)->tree
304             unless blessed $input && $input->isa('Mojo::DOM58');
305 21         47 my $tree = dclone $input->tree;
306 21 100       88 return $tree->[0] eq 'root' ? $tree : _fragment($tree);
307             }
308              
309             sub _replace {
310 30     30   60 my ($self, $parent, $child, $nodes) = @_;
311 30         68 splice @$parent, _offset($parent, $child), 1, @{_link($parent, $nodes)};
  30         62  
312 30         69 return $self->parent;
313             }
314              
315 41 100   41   197 sub _select { $_[1] ? $_[0]->grep(matches => $_[1]) : $_[0] }
316              
317             sub _siblings {
318 88     88   173 my ($tree, $tags, $tail, $i) = @_;
319              
320 88 100       211 return defined $i ? undef : [] if $tree->[0] eq 'root';
    100          
321              
322 82         131 my $nodes = _nodes(_parent($tree));
323 82         119 my $match = -1;
324 82   66     634 defined($match++) and $_ eq $tree and last for @$nodes;
      100        
325              
326 82 100       146 if ($tail) { splice @$nodes, 0, $match + 1 }
  30         63  
327 52         800 else { splice @$nodes, $match, ($#$nodes + 1) - $match }
328              
329 82 100       170 @$nodes = grep { $_->[0] eq 'tag' } @$nodes if $tags;
  171         329  
330              
331 82 100 100     339 return defined $i ? $i == -1 && !@$nodes ? undef : $nodes->[$i] : $nodes;
    100          
332             }
333              
334 1169 100   1169   3949 sub _start { $_[0][0] eq 'root' ? 1 : 4 }
335              
336             sub _text {
337 671     671   1230 my ($nodes, $all) = @_;
338              
339 671         1145 my $text = '';
340 671         1726 while (my $node = shift @$nodes) {
341 925         1388 my $type = $node->[0];
342              
343             # Text
344 925 100 100     3307 if ($type eq 'text' || $type eq 'cdata' || $type eq 'raw') {
    100 100        
      100        
345 747         2066 $text .= $node->[1];
346             }
347              
348             # Nested tag
349 121         140 elsif ($type eq 'tag' && $all) { unshift @$nodes, @{_nodes($node)} }
  121         146  
350             }
351              
352 671         2979 return $text;
353             }
354              
355             sub _wrap {
356 16     16   36 my ($self, $content, $new) = @_;
357              
358 16 100 100     29 return $self if (my $tree = $self->tree)->[0] eq 'root' && !$content;
359 15 100 100     72 return $self if $tree->[0] ne 'root' && $tree->[0] ne 'tag' && $content;
      100        
360              
361             # Find innermost tag
362 14         21 my $current;
363 14         32 my $first = $new = $self->_parse($new);
364 14         45 $current = $first while $first = _nodes($first, 1)->[0];
365 14 100       36 return $self unless $current;
366              
367             # Wrap content
368 12 100       29 if ($content) {
369 5         9 push @$current, @{_link($current, _nodes($tree))};
  5         10  
370 5         15 splice @$tree, _start($tree), $#$tree, @{_link($tree, _nodes($new))};
  5         9  
371 5         22 return $self;
372             }
373              
374             # Wrap element
375 7         17 $self->_replace(_parent($tree), $tree, _nodes($new));
376 7         21 push @$current, @{_link($current, [$tree])};
  7         15  
377 7         31 return $self;
378             }
379              
380             1;
381              
382             =encoding utf8
383              
384             =head1 NAME
385              
386             Mojo::DOM58 - Minimalistic HTML/XML DOM parser with CSS selectors
387              
388             =head1 SYNOPSIS
389              
390             use Mojo::DOM58;
391              
392             # Parse
393             my $dom = Mojo::DOM58->new('

Test

123

');
394              
395             # Find
396             say $dom->at('#b')->text;
397             say $dom->find('p')->map('text')->join("\n");
398             say $dom->find('[id]')->map(attr => 'id')->join("\n");
399              
400             # Iterate
401             $dom->find('p[id]')->reverse->each(sub { say $_->{id} });
402              
403             # Loop
404             for my $e ($dom->find('p[id]')->each) {
405             say $e->{id}, ':', $e->text;
406             }
407              
408             # Modify
409             $dom->find('div p')->last->append('

456

');
410             $dom->at('#c')->prepend($dom->new_tag('p', id => 'd', '789'));
411             $dom->find(':not(p)')->map('strip');
412              
413             # Render
414             say "$dom";
415              
416             =head1 DESCRIPTION
417              
418             L is a minimalistic and relaxed pure-perl HTML/XML DOM parser based
419             on L. It supports the L
420             and L, and
421             matching based on L. It will
422             even try to interpret broken HTML and XML, so you should not use it for
423             validation.
424              
425             =head1 FORK INFO
426              
427             L is a fork of L and tracks features and fixes to stay
428             closely compatible with upstream. It differs only in the standalone format and
429             compatibility with Perl 5.8. Any bugs or patches not related to these changes
430             should be reported directly to the L issue tracker.
431              
432             This release of L is up to date with version C<8.09> of
433             L.
434              
435             =head1 NODES AND ELEMENTS
436              
437             When we parse an HTML/XML fragment, it gets turned into a tree of nodes.
438              
439            
440            
441             Hello
442             World!
443            
444              
445             There are currently eight different kinds of nodes, C, C,
446             C, C, C, C, C and C. Elements are nodes of
447             the type C.
448              
449             root
450             |- doctype (html)
451             +- tag (html)
452             |- tag (head)
453             | +- tag (title)
454             | +- raw (Hello)
455             +- tag (body)
456             +- text (World!)
457              
458             While all node types are represented as L objects, some methods like
459             L and L only apply to elements.
460              
461             =head1 CASE-SENSITIVITY
462              
463             L defaults to HTML semantics, that means all tags and attribute
464             names are lowercased and selectors need to be lowercase as well.
465              
466             # HTML semantics
467             my $dom = Mojo::DOM58->new('

Hi!

');
468             say $dom->at('p[id]')->text;
469              
470             If an XML declaration is found, the parser will automatically switch into XML
471             mode and everything becomes case-sensitive.
472              
473             # XML semantics
474             my $dom = Mojo::DOM58->new('

Hi!

');
475             say $dom->at('P[ID]')->text;
476              
477             HTML or XML semantics can also be forced with the L method.
478              
479             # Force HTML semantics
480             my $dom = Mojo::DOM58->new->xml(0)->parse('

Hi!

');
481             say $dom->at('p[id]')->text;
482              
483             # Force XML semantics
484             my $dom = Mojo::DOM58->new->xml(1)->parse('

Hi!

');
485             say $dom->at('P[ID]')->text;
486              
487             =head1 SELECTORS
488              
489             L uses a CSS selector engine based on L. All CSS
490             selectors that make sense for a standalone parser are supported.
491              
492             =over
493              
494             =item Z<>*
495              
496             Any element.
497              
498             my $all = $dom->find('*');
499              
500             =item E
501              
502             An element of type C.
503              
504             my $title = $dom->at('title');
505              
506             =item E[foo]
507              
508             An C element with a C attribute.
509              
510             my $links = $dom->find('a[href]');
511              
512             =item E[foo="bar"]
513              
514             An C element whose C attribute value is exactly equal to C.
515              
516             my $case_sensitive = $dom->find('input[type="hidden"]');
517             my $case_sensitive = $dom->find('input[type=hidden]');
518              
519             =item E[foo="bar" i]
520              
521             An C element whose C attribute value is exactly equal to any
522             (ASCII-range) case-permutation of C. Note that this selector is
523             EXPERIMENTAL and might change without warning!
524              
525             my $case_insensitive = $dom->find('input[type="hidden" i]');
526             my $case_insensitive = $dom->find('input[type=hidden i]');
527             my $case_insensitive = $dom->find('input[class~="foo" i]');
528              
529             This selector is part of
530             L, which is still a work
531             in progress.
532              
533             =item E[foo~="bar"]
534              
535             An C element whose C attribute value is a list of whitespace-separated
536             values, one of which is exactly equal to C.
537              
538             my $foo = $dom->find('input[class~="foo"]');
539             my $foo = $dom->find('input[class~=foo]');
540              
541             =item E[foo^="bar"]
542              
543             An C element whose C attribute value begins exactly with the string
544             C.
545              
546             my $begins_with = $dom->find('input[name^="f"]');
547             my $begins_with = $dom->find('input[name^=f]');
548              
549             =item E[foo$="bar"]
550              
551             An C element whose C attribute value ends exactly with the string
552             C.
553              
554             my $ends_with = $dom->find('input[name$="o"]');
555             my $ends_with = $dom->find('input[name$=o]');
556              
557             =item E[foo*="bar"]
558              
559             An C element whose C attribute value contains the substring C.
560              
561             my $contains = $dom->find('input[name*="fo"]');
562             my $contains = $dom->find('input[name*=fo]');
563              
564             =item E[foo|="en"]
565              
566             An C element whose C attribute has a hyphen-separated list of values
567             beginning (from the left) with C.
568              
569             my $english = $dom->find('link[hreflang|=en]');
570              
571             =item E:root
572              
573             An C element, root of the document.
574              
575             my $root = $dom->at(':root');
576              
577             =item E:nth-child(n)
578              
579             An C element, the C child of its parent.
580              
581             my $third = $dom->find('div:nth-child(3)');
582             my $odd = $dom->find('div:nth-child(odd)');
583             my $even = $dom->find('div:nth-child(even)');
584             my $top3 = $dom->find('div:nth-child(-n+3)');
585              
586             =item E:nth-last-child(n)
587              
588             An C element, the C child of its parent, counting from the last one.
589              
590             my $third = $dom->find('div:nth-last-child(3)');
591             my $odd = $dom->find('div:nth-last-child(odd)');
592             my $even = $dom->find('div:nth-last-child(even)');
593             my $bottom3 = $dom->find('div:nth-last-child(-n+3)');
594              
595             =item E:nth-of-type(n)
596              
597             An C element, the C sibling of its type.
598              
599             my $third = $dom->find('div:nth-of-type(3)');
600             my $odd = $dom->find('div:nth-of-type(odd)');
601             my $even = $dom->find('div:nth-of-type(even)');
602             my $top3 = $dom->find('div:nth-of-type(-n+3)');
603              
604             =item E:nth-last-of-type(n)
605              
606             An C element, the C sibling of its type, counting from the last one.
607              
608             my $third = $dom->find('div:nth-last-of-type(3)');
609             my $odd = $dom->find('div:nth-last-of-type(odd)');
610             my $even = $dom->find('div:nth-last-of-type(even)');
611             my $bottom3 = $dom->find('div:nth-last-of-type(-n+3)');
612              
613             =item E:first-child
614              
615             An C element, first child of its parent.
616              
617             my $first = $dom->find('div p:first-child');
618              
619             =item E:last-child
620              
621             An C element, last child of its parent.
622              
623             my $last = $dom->find('div p:last-child');
624              
625             =item E:first-of-type
626              
627             An C element, first sibling of its type.
628              
629             my $first = $dom->find('div p:first-of-type');
630              
631             =item E:last-of-type
632              
633             An C element, last sibling of its type.
634              
635             my $last = $dom->find('div p:last-of-type');
636              
637             =item E:only-child
638              
639             An C element, only child of its parent.
640              
641             my $lonely = $dom->find('div p:only-child');
642              
643             =item E:only-of-type
644              
645             An C element, only sibling of its type.
646              
647             my $lonely = $dom->find('div p:only-of-type');
648              
649             =item E:empty
650              
651             An C element that has no children (including text nodes).
652              
653             my $empty = $dom->find(':empty');
654              
655             =item E:link
656              
657             An C element being the source anchor of a hyperlink of which the target is
658             not yet visited (C<:link>) or already visited (C<:visited>). Note that
659             L is not stateful, therefore C<:link> and C<:visited> yield
660             exactly the same results.
661              
662             my $links = $dom->find(':link');
663             my $links = $dom->find(':visited');
664              
665             =item E:visited
666              
667             Alias for L.
668              
669             =item E:checked
670              
671             A user interface element C which is checked (for instance a radio-button or
672             checkbox).
673              
674             my $input = $dom->find(':checked');
675              
676             =item E.warning
677              
678             An C element whose class is "warning".
679              
680             my $warning = $dom->find('div.warning');
681              
682             =item E#myid
683              
684             An C element with C equal to "myid".
685              
686             my $foo = $dom->at('div#foo');
687              
688             =item E:not(s1, s2)
689              
690             An C element that does not match either compound selector C or compound
691             selector C. Note that support for compound selectors is EXPERIMENTAL and
692             might change without warning!
693              
694             my $others = $dom->find('div p:not(:first-child, :last-child)');
695              
696             Support for compound selectors was added as part of
697             L, which is still a work
698             in progress.
699              
700             =item E:matches(s1, s2)
701              
702             An C element that matches compound selector C and/or compound selector
703             C. Note that this selector is EXPERIMENTAL and might change without warning!
704              
705             my $headers = $dom->find(':matches(section, article, aside, nav) h1');
706              
707             This selector is part of
708             L, which is still a work
709             in progress.
710              
711             =item A|E
712              
713             An C element that belongs to the namespace alias C from
714             L.
715             Key/value pairs passed to selector methods are used to declare namespace
716             aliases.
717              
718             my $elem = $dom->find('lq|elem', lq => 'http://example.com/q-markup');
719              
720             Using an empty alias searches for an element that belongs to no namespace.
721              
722             my $div = $dom->find('|div');
723              
724             =item E F
725              
726             An C element descendant of an C element.
727              
728             my $headlines = $dom->find('div h1');
729              
730             =item E E F
731              
732             An C element child of an C element.
733              
734             my $headlines = $dom->find('html > body > div > h1');
735              
736             =item E + F
737              
738             An C element immediately preceded by an C element.
739              
740             my $second = $dom->find('h1 + h2');
741              
742             =item E ~ F
743              
744             An C element preceded by an C element.
745              
746             my $second = $dom->find('h1 ~ h2');
747              
748             =item E, F, G
749              
750             Elements of type C, C and C.
751              
752             my $headlines = $dom->find('h1, h2, h3');
753              
754             =item E[foo=bar][bar=baz]
755              
756             An C element whose attributes match all following attribute selectors.
757              
758             my $links = $dom->find('a[foo^=b][foo$=ar]');
759              
760             =back
761              
762             =head1 OPERATORS
763              
764             L overloads the following operators.
765              
766             =head2 array
767              
768             my @nodes = @$dom;
769              
770             Alias for L.
771              
772             # ""
773             $dom->parse('123')->[0];
774              
775             =head2 bool
776              
777             my $bool = !!$dom;
778              
779             Always true.
780              
781             =head2 hash
782              
783             my %attrs = %$dom;
784              
785             Alias for L.
786              
787             # "test"
788             $dom->parse('
Test
')->at('div')->{id};
789              
790             =head2 stringify
791              
792             my $str = "$dom";
793              
794             Alias for L.
795              
796             =head1 FUNCTIONS
797              
798             L implements the following functions, which can be imported
799             individually.
800              
801             =head2 tag_to_html
802              
803             my $str = tag_to_html 'div', id => 'foo', 'safe content';
804              
805             Generate HTML/XML tag and render it right away. This is a significantly faster
806             alternative to L for template systems that have to generate a lot
807             of tags.
808              
809             =head1 METHODS
810              
811             L implements the following methods.
812              
813             =head2 new
814              
815             my $dom = Mojo::DOM58->new;
816             my $dom = Mojo::DOM58->new('I ♥ Mojo::DOM58!');
817              
818             Construct a new scalar-based L object and L HTML/XML
819             fragment if necessary.
820              
821             =head2 new_tag
822              
823             my $tag = Mojo::DOM58->new_tag('div');
824             my $tag = $dom->new_tag('div');
825             my $tag = $dom->new_tag('div', id => 'foo', hidden => undef);
826             my $tag = $dom->new_tag('div', 'safe content');
827             my $tag = $dom->new_tag('div', id => 'foo', 'safe content');
828             my $tag = $dom->new_tag('div', data => {mojo => 'rocks'}, 'safe content');
829             my $tag = $dom->new_tag('div', id => 'foo', sub { 'unsafe content' });
830              
831             Construct a new L object for an HTML/XML tag with or without
832             attributes and content. The C attribute may contain a hash reference with
833             key/value pairs to generate attributes from.
834              
835             # "
"
836             $dom->new_tag('br');
837              
838             # "
"
839             $dom->new_tag('div');
840              
841             # ""
842             $dom->new_tag('div', id => 'foo', hidden => undef);
843              
844             # "
test & 123
"
845             $dom->new_tag('div', 'test & 123');
846              
847             # "
test & 123
"
848             $dom->new_tag('div', id => 'foo', 'test & 123');
849              
850             # "
test & 123
""
851             $dom->new_tag('div', data => {foo => 1, Bar => 'test'}, 'test & 123');
852              
853             # "
test & 123
"
854             $dom->new_tag('div', id => 'foo', sub { 'test & 123' });
855              
856             # "
HelloMojo!
"
857             $dom->parse('
Hello
')->at('div')
858             ->append_content($dom->new_tag('b', 'Mojo!'))->root;
859              
860             =head2 all_text
861              
862             my $text = $dom->all_text;
863              
864             Extract text content from all descendant nodes of this element.
865              
866             # "foo\nbarbaz\n"
867             $dom->parse("
foo\n

bar

baz\n
")->at('div')->all_text;
868              
869             =head2 ancestors
870              
871             my $collection = $dom->ancestors;
872             my $collection = $dom->ancestors('div ~ p');
873              
874             Find all ancestor elements of this node matching the CSS selector and return a
875             L containing these elements as L
876             objects. All selectors listed in L are supported.
877              
878             # List tag names of ancestor elements
879             say $dom->ancestors->map('tag')->join("\n");
880              
881             =head2 append
882              
883             $dom = $dom->append('

I ♥ Mojo::DOM58!

');
884             $dom = $dom->append(Mojo::DOM58->new);
885              
886             Append HTML/XML fragment to this node (for all node types other than C).
887              
888             # "

Test

123

"
889             $dom->parse('

Test

')
890             ->at('h1')->append('

123

')->root;
891              
892             # "

Test 123

"
893             $dom->parse('

Test

')->at('p')
894             ->child_nodes->first->append(' 123')->root;
895              
896             =head2 append_content
897              
898             $dom = $dom->append_content('

I ♥ Mojo::DOM58!

');
899             $dom = $dom->append_content(Mojo::DOM58->new);
900              
901             Append HTML/XML fragment (for C and C nodes) or raw content to this
902             node's content.
903              
904             # "

Test123

"
905             $dom->parse('

Test

')
906             ->at('h1')->append_content('123')->root;
907              
908             # "
"
909             $dom->parse('
')
910             ->child_nodes->first->append_content('123 ')->root;
911              
912             # "

Test123

"
913             $dom->parse('

Test

')->at('p')->append_content('123')->root;
914              
915             =head2 at
916              
917             my $result = $dom->at('div ~ p');
918             my $result = $dom->at('svg|line', svg => 'http://www.w3.org/2000/svg');
919              
920             Find first descendant element of this element matching the CSS selector and
921             return it as a L object, or C if none could be found. All
922             selectors listed in L are supported.
923              
924             # Find first element with "svg" namespace definition
925             my $namespace = $dom->at('[xmlns\:svg]')->{'xmlns:svg'};
926              
927             Trailing key/value pairs can be used to declare xml namespace aliases.
928              
929             # ""
930             $dom->parse('')
931             ->at('svg|rect', svg => 'http://www.w3.org/2000/svg');
932              
933             =head2 attr
934              
935             my $hash = $dom->attr;
936             my $foo = $dom->attr('foo');
937             $dom = $dom->attr({foo => 'bar'});
938             $dom = $dom->attr(foo => 'bar');
939              
940             This element's attributes.
941              
942             # Remove an attribute
943             delete $dom->attr->{id};
944              
945             # Attribute without value
946             $dom->attr(selected => undef);
947              
948             # List id attributes
949             say $dom->find('*')->map(attr => 'id')->compact->join("\n");
950              
951             =head2 child_nodes
952              
953             my $collection = $dom->child_nodes;
954              
955             Return a L containing all child nodes of this
956             element as L objects.
957              
958             # "

123

"
959             $dom->parse('

Test123

')->at('p')->child_nodes->first->remove;
960              
961             # ""
962             $dom->parse('123')->child_nodes->first;
963              
964             # " Test "
965             $dom->parse('123')->child_nodes->last->content;
966              
967             =head2 children
968              
969             my $collection = $dom->children;
970             my $collection = $dom->children('div ~ p');
971              
972             Find all child elements of this element matching the CSS selector and return a
973             L containing these elements as L
974             objects. All selectors listed in L are supported.
975              
976             # Show tag name of random child element
977             say $dom->children->shuffle->first->tag;
978              
979             =head2 content
980              
981             my $str = $dom->content;
982             $dom = $dom->content('

I ♥ Mojo::DOM58!

');
983             $dom = $dom->content(Mojo::DOM58->new);
984              
985             Return this node's content or replace it with HTML/XML fragment (for C
986             and C nodes) or raw content.
987              
988             # "Test"
989             $dom->parse('
Test
')->at('div')->content;
990              
991             # "

123

"
992             $dom->parse('

Test

')->at('h1')->content('123')->root;
993              
994             # "

123

"
995             $dom->parse('

Test

')->at('p')->content('123')->root;
996              
997             # "

"
998             $dom->parse('

Test

')->at('h1')->content('')->root;
999              
1000             # " Test "
1001             $dom->parse('
')->child_nodes->first->content;
1002              
1003             # "
456
"
1004             $dom->parse('
456
')
1005             ->at('div')->child_nodes->first->content(' 123 ')->root;
1006              
1007             =head2 descendant_nodes
1008              
1009             my $collection = $dom->descendant_nodes;
1010              
1011             Return a L containing all descendant nodes of
1012             this element as L objects.
1013              
1014             # "

123

"
1015             $dom->parse('

123

')
1016             ->descendant_nodes->grep(sub { $_->type eq 'comment' })
1017             ->map('remove')->first;
1018              
1019             # "

testtest

"
1020             $dom->parse('

123456

')
1021             ->at('p')->descendant_nodes->grep(sub { $_->type eq 'text' })
1022             ->map(content => 'test')->first->root;
1023              
1024             =head2 find
1025              
1026             my $collection = $dom->find('div ~ p');
1027             my $collection = $dom->find('svg|line', svg => 'http://www.w3.org/2000/svg');
1028              
1029             Find all descendant elements of this element matching the CSS selector and
1030             return a L containing these elements as
1031             L objects. All selectors listed in L are supported.
1032              
1033             # Find a specific element and extract information
1034             my $id = $dom->find('div')->[23]{id};
1035              
1036             # Extract information from multiple elements
1037             my @headers = $dom->find('h1, h2, h3')->map('text')->each;
1038              
1039             # Count all the different tags
1040             my $hash = $dom->find('*')->reduce(sub { $a->{$b->tag}++; $a }, {});
1041              
1042             # Find elements with a class that contains dots
1043             my @divs = $dom->find('div.foo\.bar')->each;
1044              
1045             Trailing key/value pairs can be used to declare xml namespace aliases.
1046              
1047             # ""
1048             $dom->parse('')
1049             ->find('svg|rect', svg => 'http://www.w3.org/2000/svg')->first;
1050              
1051             =head2 following
1052              
1053             my $collection = $dom->following;
1054             my $collection = $dom->following('div ~ p');
1055              
1056             Find all sibling elements after this node matching the CSS selector and return
1057             a L containing these elements as
1058             L objects. All selectors listed in L are supported.
1059              
1060             # List tags of sibling elements after this node
1061             say $dom->following->map('tag')->join("\n");
1062              
1063             =head2 following_nodes
1064              
1065             my $collection = $dom->following_nodes;
1066              
1067             Return a L containing all sibling nodes after
1068             this node as L objects.
1069              
1070             # "C"
1071             $dom->parse('

A

C')->at('p')->following_nodes->last->content;
1072              
1073             =head2 matches
1074              
1075             my $bool = $dom->matches('div ~ p');
1076             my $bool = $dom->matches('svg|line', svg => 'http://www.w3.org/2000/svg');
1077              
1078             Check if this element matches the CSS selector. All selectors listed in
1079             L are supported.
1080              
1081             # True
1082             $dom->parse('

A

')->at('p')->matches('.a');
1083             $dom->parse('

A

')->at('p')->matches('p[class]');
1084              
1085             # False
1086             $dom->parse('

A

')->at('p')->matches('.b');
1087             $dom->parse('

A

')->at('p')->matches('p[id]');
1088              
1089             Trailing key/value pairs can be used to declare xml namespace aliases.
1090              
1091             # True
1092             $dom->parse('')
1093             ->matches('svg|rect', svg => 'http://www.w3.org/2000/svg');
1094              
1095             =head2 namespace
1096              
1097             my $namespace = $dom->namespace;
1098              
1099             Find this element's namespace, or return C if none could be found.
1100              
1101             # Find namespace for an element with namespace prefix
1102             my $namespace = $dom->at('svg > svg\:circle')->namespace;
1103              
1104             # Find namespace for an element that may or may not have a namespace prefix
1105             my $namespace = $dom->at('svg > circle')->namespace;
1106              
1107             =head2 next
1108              
1109             my $sibling = $dom->next;
1110              
1111             Return L object for next sibling element, or C if there are
1112             no more siblings.
1113              
1114             # "

123

"
1115             $dom->parse('

Test

123

')->at('h1')->next;
1116              
1117             =head2 next_node
1118              
1119             my $sibling = $dom->next_node;
1120              
1121             Return L object for next sibling node, or C if there are no
1122             more siblings.
1123              
1124             # "456"
1125             $dom->parse('

123456

')
1126             ->at('b')->next_node->next_node;
1127              
1128             # " Test "
1129             $dom->parse('

123456

')
1130             ->at('b')->next_node->content;
1131              
1132             =head2 parent
1133              
1134             my $parent = $dom->parent;
1135              
1136             Return L object for parent of this node, or C if this node
1137             has no parent.
1138              
1139             # "Test"
1140             $dom->parse('

Test

')->at('i')->parent;
1141              
1142             =head2 parse
1143              
1144             $dom = $dom->parse('I ♥ Mojo::DOM58!');
1145              
1146             Parse HTML/XML fragment.
1147              
1148             # Parse XML
1149             my $dom = Mojo::DOM58->new->xml(1)->parse('I ♥ Mojo::DOM58!');
1150              
1151             =head2 preceding
1152              
1153             my $collection = $dom->preceding;
1154             my $collection = $dom->preceding('div ~ p');
1155              
1156             Find all sibling elements before this node matching the CSS selector and return
1157             a L containing these elements as
1158             L objects. All selectors listed in L are supported.
1159              
1160             # List tags of sibling elements before this node
1161             say $dom->preceding->map('tag')->join("\n");
1162              
1163             =head2 preceding_nodes
1164              
1165             my $collection = $dom->preceding_nodes;
1166              
1167             Return a L containing all sibling nodes
1168             before this node as L objects.
1169              
1170             # "A"
1171             $dom->parse('A

C

')->at('p')->preceding_nodes->first->content;
1172              
1173             =head2 prepend
1174              
1175             $dom = $dom->prepend('

I ♥ Mojo::DOM58!

');
1176             $dom = $dom->prepend(Mojo::DOM58->new);
1177              
1178             Prepend HTML/XML fragment to this node (for all node types other than C).
1179              
1180             # "

Test

123

"
1181             $dom->parse('

123

')
1182             ->at('h2')->prepend('

Test

')->root;
1183              
1184             # "

Test 123

"
1185             $dom->parse('

123

')
1186             ->at('p')->child_nodes->first->prepend('Test ')->root;
1187              
1188             =head2 prepend_content
1189              
1190             $dom = $dom->prepend_content('

I ♥ Mojo::DOM58!

');
1191             $dom = $dom->prepend_content(Mojo::DOM58->new);
1192              
1193             Prepend HTML/XML fragment (for C and C nodes) or raw content to this
1194             node's content.
1195              
1196             # "

Test123

"
1197             $dom->parse('

123

')
1198             ->at('h2')->prepend_content('Test')->root;
1199              
1200             # "
"
1201             $dom->parse('
')
1202             ->child_nodes->first->prepend_content(' Test')->root;
1203              
1204             # "

123Test

"
1205             $dom->parse('

Test

')->at('p')->prepend_content('123')->root;
1206              
1207             =head2 previous
1208              
1209             my $sibling = $dom->previous;
1210              
1211             Return L object for previous sibling element, or C if there
1212             are no more siblings.
1213              
1214             # "

Test

"
1215             $dom->parse('

Test

123

')->at('h2')->previous;
1216              
1217             =head2 previous_node
1218              
1219             my $sibling = $dom->previous_node;
1220              
1221             Return L object for previous sibling node, or C if there are
1222             no more siblings.
1223              
1224             # "123"
1225             $dom->parse('

123456

')
1226             ->at('b')->previous_node->previous_node;
1227              
1228             # " Test "
1229             $dom->parse('

123456

')
1230             ->at('b')->previous_node->content;
1231              
1232             =head2 remove
1233              
1234             my $parent = $dom->remove;
1235              
1236             Remove this node and return L (for C nodes) or L.
1237              
1238             # "
"
1239             $dom->parse('

Test

')->at('h1')->remove;
1240              
1241             # "

456

"
1242             $dom->parse('

123456

')
1243             ->at('p')->child_nodes->first->remove->root;
1244              
1245             =head2 replace
1246              
1247             my $parent = $dom->replace('
I ♥ Mojo::DOM58!
');
1248             my $parent = $dom->replace(Mojo::DOM58->new);
1249              
1250             Replace this node with HTML/XML fragment and return L (for C
1251             nodes) or L.
1252              
1253             # "

123

"
1254             $dom->parse('

Test

')->at('h1')->replace('

123

');
1255              
1256             # "

123

"
1257             $dom->parse('

Test

')
1258             ->at('p')->child_nodes->[0]->replace('123')->root;
1259              
1260             =head2 root
1261              
1262             my $root = $dom->root;
1263              
1264             Return L object for C node.
1265              
1266             =head2 selector
1267              
1268             my $selector = $dom->selector;
1269              
1270             Get a unique CSS selector for this element.
1271              
1272             # "ul:nth-child(1) > li:nth-child(2)"
1273             $dom->parse('
  • Test
  • 123
')->find('li')->last->selector;
1274              
1275             # "p:nth-child(1) > b:nth-child(1) > i:nth-child(1)"
1276             $dom->parse('

Test

')->at('i')->selector;
1277              
1278             =head2 strip
1279              
1280             my $parent = $dom->strip;
1281              
1282             Remove this element while preserving its content and return L.
1283              
1284             # "
Test
"
1285             $dom->parse('

Test

')->at('h1')->strip;
1286              
1287             =head2 tag
1288              
1289             my $tag = $dom->tag;
1290             $dom = $dom->tag('div');
1291              
1292             This element's tag name.
1293              
1294             # List tag names of child elements
1295             say $dom->children->map('tag')->join("\n");
1296              
1297             =head2 tap
1298              
1299             $dom = $dom->tap(sub {...});
1300              
1301             Equivalent to L.
1302              
1303             =head2 text
1304              
1305             my $text = $dom->text;
1306              
1307             Extract text content from this element only (not including child elements).
1308              
1309             # "bar"
1310             $dom->parse("
foo

bar

baz
")->at('p')->text;
1311              
1312             # "foo\nbaz\n"
1313             $dom->parse("
foo\n

bar

baz\n
")->at('div')->text;
1314              
1315             =head2 to_string
1316              
1317             my $str = $dom->to_string;
1318              
1319             Render this node and its content to HTML/XML.
1320              
1321             # "Test"
1322             $dom->parse('
Test
')->at('div b')->to_string;
1323              
1324             =head2 tree
1325              
1326             my $tree = $dom->tree;
1327             $dom = $dom->tree(['root']);
1328              
1329             Document Object Model. Note that this structure should only be used very
1330             carefully since it is very dynamic.
1331              
1332             =head2 type
1333              
1334             my $type = $dom->type;
1335              
1336             This node's type, usually C, C, C, C, C,
1337             C, C or C.
1338              
1339             # "cdata"
1340             $dom->parse('')->child_nodes->first->type;
1341              
1342             # "comment"
1343             $dom->parse('')->child_nodes->first->type;
1344              
1345             # "doctype"
1346             $dom->parse('')->child_nodes->first->type;
1347              
1348             # "pi"
1349             $dom->parse('')->child_nodes->first->type;
1350              
1351             # "raw"
1352             $dom->parse('Test')->at('title')->child_nodes->first->type;
1353              
1354             # "root"
1355             $dom->parse('

Test

')->type;
1356              
1357             # "tag"
1358             $dom->parse('

Test

')->at('p')->type;
1359              
1360             # "text"
1361             $dom->parse('

Test

')->at('p')->child_nodes->first->type;
1362              
1363             =head2 val
1364              
1365             my $value = $dom->val;
1366              
1367             Extract value from form element (such as C
1368             C')->at('textarea')->val;
1378              
1379             # "c"
1380             $dom->parse('')->at('option')->val;
1381              
1382             # "d"
1383             $dom->parse('')
1384             ->at('select')->val;
1385              
1386             # "e"
1387             $dom->parse('')
1388             ->at('select')->val->[0];
1389              
1390             # "on"
1391             $dom->parse('')->at('input')->val;
1392              
1393             =head2 with_roles
1394              
1395             my $new_class = Mojo::DOM58->with_roles('Mojo::DOM58::Role::One');
1396             my $new_class = Mojo::DOM58->with_roles('+One', '+Two');
1397             $dom = $dom->with_roles('+One', '+Two');
1398              
1399             Equivalent to L. Note that role support depends on
1400             L (2.000001+).
1401              
1402             =head2 wrap
1403              
1404             $dom = $dom->wrap('
');
1405             $dom = $dom->wrap(Mojo::DOM58->new);
1406              
1407             Wrap HTML/XML fragment around this node (for all node types other than C),
1408             placing it as the last child of the first innermost element.
1409              
1410             # "

123Test

"
1411             $dom->parse('Test')->at('b')->wrap('

123

')->root;
1412              
1413             # "

Test

123
"
1414             $dom->parse('Test')->at('b')->wrap('

123
')->root;
1415              
1416             # "

Test

123

"
1417             $dom->parse('Test')->at('b')->wrap('

123

')->root;
1418              
1419             # "

Test

"
1420             $dom->parse('

Test

')->at('p')->child_nodes->first->wrap('')->root;
1421              
1422             =head2 wrap_content
1423              
1424             $dom = $dom->wrap_content('
');
1425             $dom = $dom->wrap_content(Mojo::DOM58->new);
1426              
1427             Wrap HTML/XML fragment around this node's content (for C and C
1428             nodes), placing it as the last children of the first innermost element.
1429              
1430             # "

123Test

"
1431             $dom->parse('

Test

')->at('p')->wrap_content('123')->root;

1432              
1433             # "

Test

123

"
1434             $dom->parse('Test')->wrap_content('

123

');
1435              
1436             =head2 xml
1437              
1438             my $bool = $dom->xml;
1439             $dom = $dom->xml($bool);
1440              
1441             Disable HTML semantics in parser and activate case-sensitivity, defaults to
1442             auto detection based on XML declarations.
1443              
1444             =head1 COLLECTION METHODS
1445              
1446             Some L methods return an array-based collection object based on
1447             L, which can either be accessed directly as an array
1448             reference, or with the following methods.
1449              
1450             # Chain methods
1451             $collection->map(sub { ucfirst })->shuffle->each(sub {
1452             my ($word, $num) = @_;
1453             say "$num: $word";
1454             });
1455              
1456             # Access array directly to manipulate collection
1457             $collection->[23] += 100;
1458             say for @$collection;
1459              
1460             =head2 compact
1461              
1462             my $new = $collection->compact;
1463              
1464             Create a new L with all elements that are
1465             defined and not an empty string.
1466              
1467             # $collection contains (0, 1, undef, 2, '', 3)
1468             $collection->compact->join(', '); # "0, 1, 2, 3"
1469              
1470             =head2 each
1471              
1472             my @elements = $collection->each;
1473             $collection = $collection->each(sub {...});
1474              
1475             Evaluate callback for each element in collection or return all elements as a
1476             list if none has been provided. The element will be the first argument passed
1477             to the callback and is also available as C<$_>.
1478              
1479             # Make a numbered list
1480             $collection->each(sub {
1481             my ($e, $num) = @_;
1482             say "$num: $e";
1483             });
1484              
1485             =head2 first
1486              
1487             my $first = $collection->first;
1488             my $first = $collection->first(qr/foo/);
1489             my $first = $collection->first(sub {...});
1490             my $first = $collection->first($method);
1491             my $first = $collection->first($method, @args);
1492              
1493             Evaluate regular expression/callback for, or call method on, each element in
1494             collection and return the first one that matched the regular expression, or for
1495             which the callback/method returned true. The element will be the first argument
1496             passed to the callback and is also available as C<$_>.
1497              
1498             # Longer version
1499             my $first = $collection->first(sub { $_->$method(@args) });
1500              
1501             # Find first value that contains the word "mojo"
1502             my $interesting = $collection->first(qr/mojo/i);
1503              
1504             # Find first value that is greater than 5
1505             my $greater = $collection->first(sub { $_ > 5 });
1506              
1507             =head2 flatten
1508              
1509             my $new = $collection->flatten;
1510              
1511             Flatten nested collections/arrays recursively and create a new
1512             L with all elements.
1513              
1514             # $collection contains (1, [2, [3, 4], 5, [6]], 7)
1515             $collection->flatten->join(', '); # "1, 2, 3, 4, 5, 6, 7"
1516              
1517             =head2 grep
1518              
1519             my $new = $collection->grep(qr/foo/);
1520             my $new = $collection->grep(sub {...});
1521             my $new = $collection->grep($method);
1522             my $new = $collection->grep($method, @args);
1523              
1524             Evaluate regular expression/callback for, or call method on, each element in
1525             collection and create a new L with all
1526             elements that matched the regular expression, or for which the callback/method
1527             returned true. The element will be the first argument passed to the callback
1528             and is also available as C<$_>.
1529              
1530             # Longer version
1531             my $new = $collection->grep(sub { $_->$method(@args) });
1532              
1533             # Find all values that contain the word "mojo"
1534             my $interesting = $collection->grep(qr/mojo/i);
1535              
1536             # Find all values that are greater than 5
1537             my $greater = $collection->grep(sub { $_ > 5 });
1538              
1539             =head2 join
1540              
1541             my $stream = $collection->join;
1542             my $stream = $collection->join("\n");
1543              
1544             Turn collection into string.
1545              
1546             # Join all values with commas
1547             $collection->join(', ');
1548              
1549             =head2 last
1550              
1551             my $last = $collection->last;
1552              
1553             Return the last element in collection.
1554              
1555             =head2 map
1556              
1557             my $new = $collection->map(sub {...});
1558             my $new = $collection->map($method);
1559             my $new = $collection->map($method, @args);
1560              
1561             Evaluate callback for, or call method on, each element in collection and create
1562             a new L from the results. The element will be
1563             the first argument passed to the callback and is also available as C<$_>.
1564              
1565             # Longer version
1566             my $new = $collection->map(sub { $_->$method(@args) });
1567              
1568             # Append the word "mojo" to all values
1569             my $domified = $collection->map(sub { $_ . 'mojo' });
1570              
1571             =head2 reduce
1572              
1573             my $result = $collection->reduce(sub {...});
1574             my $result = $collection->reduce(sub {...}, $initial);
1575              
1576             Reduce elements in collection with callback, the first element will be used as
1577             initial value if none has been provided.
1578              
1579             # Calculate the sum of all values
1580             my $sum = $collection->reduce(sub { $a + $b });
1581              
1582             # Count how often each value occurs in collection
1583             my $hash = $collection->reduce(sub { $a->{$b}++; $a }, {});
1584              
1585             =head2 reverse
1586              
1587             my $new = $collection->reverse;
1588              
1589             Create a new L with all elements in reverse
1590             order.
1591              
1592             =head2 slice
1593              
1594             my $new = $collection->slice(4 .. 7);
1595              
1596             Create a new L with all selected elements.
1597              
1598             # $collection contains ('A', 'B', 'C', 'D', 'E')
1599             $collection->slice(1, 2, 4)->join(' '); # "B C E"
1600              
1601             =head2 shuffle
1602              
1603             my $new = $collection->shuffle;
1604              
1605             Create a new L with all elements in random
1606             order.
1607              
1608             =head2 size
1609              
1610             my $size = $collection->size;
1611              
1612             Number of elements in collection.
1613              
1614             =head2 sort
1615              
1616             my $new = $collection->sort;
1617             my $new = $collection->sort(sub {...});
1618              
1619             Sort elements based on return value of callback and create a new
1620             L from the results.
1621              
1622             # Sort values case-insensitive
1623             my $case_insensitive = $collection->sort(sub { uc($a) cmp uc($b) });
1624              
1625             =head2 tap
1626              
1627             $collection = $collection->tap(sub {...});
1628              
1629             Equivalent to L.
1630              
1631             =head2 to_array
1632              
1633             my $array = $collection->to_array;
1634              
1635             Turn collection into array reference.
1636              
1637             =head2 uniq
1638              
1639             my $new = $collection->uniq;
1640             my $new = $collection->uniq(sub {...});
1641             my $new = $collection->uniq($method);
1642             my $new = $collection->uniq($method, @args);
1643              
1644             Create a new L without duplicate elements,
1645             using the string representation of either the elements or the return value of
1646             the callback/method to decide uniqueness. Note that C and empty string
1647             are treated the same.
1648              
1649             # Longer version
1650             my $new = $collection->uniq(sub { $_->$method(@args) });
1651              
1652             # $collection contains ('foo', 'bar', 'bar', 'baz')
1653             $collection->uniq->join(' '); # "foo bar baz"
1654              
1655             # $collection contains ([1, 2], [2, 1], [3, 2])
1656             $collection->uniq(sub{ $_->[1] })->to_array; # "[[1, 2], [2, 1]]"
1657              
1658             =head2 with_roles
1659              
1660             $collection = $collection->with_roles('Mojo::Collection::Role::One');
1661              
1662             Equivalent to L. Note that role support depends on
1663             L (2.000001+).
1664              
1665             =head1 BUGS
1666              
1667             Report issues related to the format of this distribution or Perl 5.8 support to
1668             the public bugtracker. Any other issues should be reported directly to the
1669             upstream L issue tracker.
1670              
1671             =head1 AUTHOR
1672              
1673             Dan Book
1674              
1675             Code and tests adapted from L, a lightweight DOM parser by the L team.
1676              
1677             =head1 CONTRIBUTORS
1678              
1679             =over
1680              
1681             =item Matt S Trout (mst)
1682              
1683             =back
1684              
1685             =head1 COPYRIGHT AND LICENSE
1686              
1687             Copyright (c) 2008-2016 Sebastian Riedel and others.
1688              
1689             Copyright (c) 2016 L and L for adaptation to standalone format.
1690              
1691             This is free software, licensed under:
1692              
1693             The Artistic License 2.0 (GPL Compatible)
1694              
1695             =head1 SEE ALSO
1696              
1697             L, L, L, L, L
1698              
1699             =for Pod::Coverage TO_JSON
1700              
1701             =cut