reference collection methods section
[catagits/DOM-Tiny.git] / README.pod
CommitLineData
d6512b50 1=pod
2
3=encoding utf8
4
78ba4051 5=for Pod::Coverage TO_JSON
6
d6512b50 7=head1 NAME
8
9DOM::Tiny - Minimalistic HTML/XML DOM parser with CSS selectors
10
11=head1 SYNOPSIS
12
13 use DOM::Tiny;
14
15 # Parse
16 my $dom = DOM::Tiny->new('<div><p id="a">Test</p><p id="b">123</p></div>');
17
18 # Find
19 say $dom->at('#b')->text;
20 say $dom->find('p')->map('text')->join("\n");
21 say $dom->find('[id]')->map(attr => 'id')->join("\n");
22
23 # Iterate
24 $dom->find('p[id]')->reverse->each(sub { say $_->{id} });
25
26 # Loop
27 for my $e ($dom->find('p[id]')->each) {
28 say $e->{id}, ':', $e->text;
29 }
30
31 # Modify
32 $dom->find('div p')->last->append('<p id="c">456</p>');
33 $dom->find(':not(p)')->map('strip');
34
35 # Render
36 say "$dom";
37
38=head1 DESCRIPTION
39
5a70ee9d 40L<DOM::Tiny> is a minimalistic and relaxed pure-perl HTML/XML DOM parser with
41support for the L<HTML Living Standard|https://html.spec.whatwg.org/> and
42L<CSS3 selectors|http://www.w3.org/TR/selectors/> based on L<Mojo::DOM>. It
43will even try to interpret broken HTML and XML, so you should not use it for
44validation.
d6512b50 45
46=head1 NODES AND ELEMENTS
47
48When we parse an HTML/XML fragment, it gets turned into a tree of nodes.
49
50 <!DOCTYPE html>
51 <html>
52 <head><title>Hello</title></head>
53 <body>World!</body>
54 </html>
55
56There are currently eight different kinds of nodes, C<cdata>, C<comment>,
57C<doctype>, C<pi>, C<raw>, C<root>, C<tag> and C<text>. Elements are nodes of
58the type C<tag>.
59
60 root
61 |- doctype (html)
62 +- tag (html)
63 |- tag (head)
64 | +- tag (title)
65 | +- raw (Hello)
66 +- tag (body)
67 +- text (World!)
68
69While all node types are represented as L<DOM::Tiny> objects, some methods like
70L</"attr"> and L</"namespace"> only apply to elements.
71
72=head1 CASE-SENSITIVITY
73
74L<DOM::Tiny> defaults to HTML semantics, that means all tags and attribute
75names are lowercased and selectors need to be lowercase as well.
76
77 # HTML semantics
78 my $dom = DOM::Tiny->new('<P ID="greeting">Hi!</P>');
79 say $dom->at('p[id]')->text;
80
81If XML processing instructions are found, the parser will automatically switch
82into XML mode and everything becomes case-sensitive.
83
84 # XML semantics
85 my $dom = DOM::Tiny->new('<?xml version="1.0"?><P ID="greeting">Hi!</P>');
86 say $dom->at('P[ID]')->text;
87
88XML detection can also be disabled with the L</"xml"> method.
89
90 # Force XML semantics
91 my $dom = DOM::Tiny->new->xml(1)->parse('<P ID="greeting">Hi!</P>');
92 say $dom->at('P[ID]')->text;
93
94 # Force HTML semantics
95 my $dom = DOM::Tiny->new->xml(0)->parse('<P ID="greeting">Hi!</P>');
96 say $dom->at('p[id]')->text;
97
98=head1 METHODS
99
100L<DOM::Tiny> implements the following methods.
101
3793c28f 102=head2 new
103
104 my $dom = DOM::Tiny->new;
105 my $dom = DOM::Tiny->new('<foo bar="baz">I ♥ DOM::Tiny!</foo>');
106
107Construct a new scalar-based L<DOM::Tiny> object and L</"parse"> HTML/XML
108fragment if necessary.
109
d6512b50 110=head2 all_text
111
112 my $trimmed = $dom->all_text;
113 my $untrimmed = $dom->all_text(0);
114
115Extract text content from all descendant nodes of this element, smart
116whitespace trimming is enabled by default.
117
118 # "foo bar baz"
119 $dom->parse("<div>foo\n<p>bar</p>baz\n</div>")->at('div')->all_text;
120
121 # "foo\nbarbaz\n"
122 $dom->parse("<div>foo\n<p>bar</p>baz\n</div>")->at('div')->all_text(0);
123
124=head2 ancestors
125
126 my $collection = $dom->ancestors;
127 my $collection = $dom->ancestors('div ~ p');
128
129Find all ancestor elements of this node matching the CSS selector and return a
8563f527 130L<collection|/"COLLECTION METHODS"> containing these elements as L<DOM::Tiny>
d6512b50 131objects. All selectors from L<DOM::Tiny::CSS/"SELECTORS"> are supported.
132
133 # List tag names of ancestor elements
134 say $dom->ancestors->map('tag')->join("\n");
135
136=head2 append
137
138 $dom = $dom->append('<p>I ♥ DOM::Tiny!</p>');
139
140Append HTML/XML fragment to this node.
141
142 # "<div><h1>Test</h1><h2>123</h2></div>"
143 $dom->parse('<div><h1>Test</h1></div>')
144 ->at('h1')->append('<h2>123</h2>')->root;
145
146 # "<p>Test 123</p>"
147 $dom->parse('<p>Test</p>')->at('p')
148 ->child_nodes->first->append(' 123')->root;
149
150=head2 append_content
151
152 $dom = $dom->append_content('<p>I ♥ DOM::Tiny!</p>');
153
154Append HTML/XML fragment (for C<root> and C<tag> nodes) or raw content to this
155node's content.
156
157 # "<div><h1>Test123</h1></div>"
158 $dom->parse('<div><h1>Test</h1></div>')
159 ->at('h1')->append_content('123')->root;
160
161 # "<!-- Test 123 --><br>"
162 $dom->parse('<!-- Test --><br>')
163 ->child_nodes->first->append_content('123 ')->root;
164
165 # "<p>Test<i>123</i></p>"
166 $dom->parse('<p>Test</p>')->at('p')->append_content('<i>123</i>')->root;
167
168=head2 at
169
170 my $result = $dom->at('div ~ p');
171
172Find first descendant element of this element matching the CSS selector and
173return it as a L<DOM::Tiny> object or return C<undef> if none could be found.
174All selectors from L<DOM::Tiny::CSS/"SELECTORS"> are supported.
175
176 # Find first element with "svg" namespace definition
177 my $namespace = $dom->at('[xmlns\:svg]')->{'xmlns:svg'};
178
179=head2 attr
180
181 my $hash = $dom->attr;
182 my $foo = $dom->attr('foo');
183 $dom = $dom->attr({foo => 'bar'});
184 $dom = $dom->attr(foo => 'bar');
185
186This element's attributes.
187
188 # Remove an attribute
189 delete $dom->attr->{id};
190
191 # Attribute without value
192 $dom->attr(selected => undef);
193
194 # List id attributes
195 say $dom->find('*')->map(attr => 'id')->compact->join("\n");
196
197=head2 child_nodes
198
199 my $collection = $dom->child_nodes;
200
8563f527 201Return a L<collection|/"COLLECTION METHODS"> containing all child nodes of this
d6512b50 202element as L<DOM::Tiny> objects.
203
204 # "<p><b>123</b></p>"
205 $dom->parse('<p>Test<b>123</b></p>')->at('p')->child_nodes->first->remove;
206
207 # "<!DOCTYPE html>"
208 $dom->parse('<!DOCTYPE html><b>123</b>')->child_nodes->first;
209
210 # " Test "
211 $dom->parse('<b>123</b><!-- Test -->')->child_nodes->last->content;
212
213=head2 children
214
215 my $collection = $dom->children;
216 my $collection = $dom->children('div ~ p');
217
218Find all child elements of this element matching the CSS selector and return a
8563f527 219L<collection|/"COLLECTION METHODS"> containing these elements as L<DOM::Tiny>
d6512b50 220objects. All selectors from L<DOM::Tiny::CSS/"SELECTORS"> are supported.
221
222 # Show tag name of random child element
223 say $dom->children->shuffle->first->tag;
224
225=head2 content
226
227 my $str = $dom->content;
228 $dom = $dom->content('<p>I ♥ DOM::Tiny!</p>');
229
230Return this node's content or replace it with HTML/XML fragment (for C<root>
231and C<tag> nodes) or raw content.
232
233 # "<b>Test</b>"
234 $dom->parse('<div><b>Test</b></div>')->at('div')->content;
235
236 # "<div><h1>123</h1></div>"
237 $dom->parse('<div><h1>Test</h1></div>')->at('h1')->content('123')->root;
238
239 # "<p><i>123</i></p>"
240 $dom->parse('<p>Test</p>')->at('p')->content('<i>123</i>')->root;
241
242 # "<div><h1></h1></div>"
243 $dom->parse('<div><h1>Test</h1></div>')->at('h1')->content('')->root;
244
245 # " Test "
246 $dom->parse('<!-- Test --><br>')->child_nodes->first->content;
247
248 # "<div><!-- 123 -->456</div>"
249 $dom->parse('<div><!-- Test -->456</div>')
250 ->at('div')->child_nodes->first->content(' 123 ')->root;
251
252=head2 descendant_nodes
253
254 my $collection = $dom->descendant_nodes;
255
8563f527 256Return a L<collection|/"COLLECTION METHODS"> containing all descendant nodes of
d6512b50 257this element as L<DOM::Tiny> objects.
258
259 # "<p><b>123</b></p>"
260 $dom->parse('<p><!-- Test --><b>123<!-- 456 --></b></p>')
261 ->descendant_nodes->grep(sub { $_->type eq 'comment' })
262 ->map('remove')->first;
263
264 # "<p><b>test</b>test</p>"
265 $dom->parse('<p><b>123</b>456</p>')
266 ->at('p')->descendant_nodes->grep(sub { $_->type eq 'text' })
267 ->map(content => 'test')->first->root;
268
269=head2 find
270
271 my $collection = $dom->find('div ~ p');
272
273Find all descendant elements of this element matching the CSS selector and
8563f527 274return a L<collection|/"COLLECTION METHODS"> containing these elements as
d6512b50 275L<DOM::Tiny> objects. All selectors from L<DOM::Tiny::CSS/"SELECTORS"> are
276supported.
277
278 # Find a specific element and extract information
279 my $id = $dom->find('div')->[23]{id};
280
281 # Extract information from multiple elements
282 my @headers = $dom->find('h1, h2, h3')->map('text')->each;
283
284 # Count all the different tags
285 my $hash = $dom->find('*')->reduce(sub { $a->{$b->tag}++; $a }, {});
286
287 # Find elements with a class that contains dots
288 my @divs = $dom->find('div.foo\.bar')->each;
289
290=head2 following
291
292 my $collection = $dom->following;
293 my $collection = $dom->following('div ~ p');
294
295Find all sibling elements after this node matching the CSS selector and return
8563f527 296a L<collection|/"COLLECTION METHODS"> containing these elements as L<DOM::Tiny>
d6512b50 297objects. All selectors from L<DOM::Tiny::CSS/"SELECTORS"> are supported.
298
299 # List tags of sibling elements after this node
300 say $dom->following->map('tag')->join("\n");
301
302=head2 following_nodes
303
304 my $collection = $dom->following_nodes;
305
8563f527 306Return a L<collection|/"COLLECTION METHODS"> containing all sibling nodes after
d6512b50 307this node as L<DOM::Tiny> objects.
308
309 # "C"
310 $dom->parse('<p>A</p><!-- B -->C')->at('p')->following_nodes->last->content;
311
312=head2 matches
313
314 my $bool = $dom->matches('div ~ p');
315
316Check if this element matches the CSS selector. All selectors from
317L<DOM::Tiny::CSS/"SELECTORS"> are supported.
318
319 # True
320 $dom->parse('<p class="a">A</p>')->at('p')->matches('.a');
321 $dom->parse('<p class="a">A</p>')->at('p')->matches('p[class]');
322
323 # False
324 $dom->parse('<p class="a">A</p>')->at('p')->matches('.b');
325 $dom->parse('<p class="a">A</p>')->at('p')->matches('p[id]');
326
327=head2 namespace
328
329 my $namespace = $dom->namespace;
330
331Find this element's namespace or return C<undef> if none could be found.
332
333 # Find namespace for an element with namespace prefix
334 my $namespace = $dom->at('svg > svg\:circle')->namespace;
335
336 # Find namespace for an element that may or may not have a namespace prefix
337 my $namespace = $dom->at('svg > circle')->namespace;
338
d6512b50 339=head2 next
340
341 my $sibling = $dom->next;
342
343Return L<DOM::Tiny> object for next sibling element or C<undef> if there are no
344more siblings.
345
346 # "<h2>123</h2>"
347 $dom->parse('<div><h1>Test</h1><h2>123</h2></div>')->at('h1')->next;
348
349=head2 next_node
350
351 my $sibling = $dom->next_node;
352
353Return L<DOM::Tiny> object for next sibling node or C<undef> if there are no
354more siblings.
355
356 # "456"
357 $dom->parse('<p><b>123</b><!-- Test -->456</p>')
358 ->at('b')->next_node->next_node;
359
360 # " Test "
361 $dom->parse('<p><b>123</b><!-- Test -->456</p>')
362 ->at('b')->next_node->content;
363
364=head2 parent
365
366 my $parent = $dom->parent;
367
368Return L<DOM::Tiny> object for parent of this node or C<undef> if this node has
369no parent.
370
371=head2 parse
372
373 $dom = $dom->parse('<foo bar="baz">I ♥ DOM::Tiny!</foo>');
374
375Parse HTML/XML fragment with L<DOM::Tiny::HTML>.
376
377 # Parse XML
378 my $dom = DOM::Tiny->new->xml(1)->parse($xml);
379
380=head2 preceding
381
382 my $collection = $dom->preceding;
383 my $collection = $dom->preceding('div ~ p');
384
385Find all sibling elements before this node matching the CSS selector and return
8563f527 386a L<collection|/"COLLECTION METHODS"> containing these elements as L<DOM::Tiny>
d6512b50 387objects. All selectors from L<DOM::Tiny::CSS/"SELECTORS"> are supported.
388
389 # List tags of sibling elements before this node
390 say $dom->preceding->map('tag')->join("\n");
391
392=head2 preceding_nodes
393
394 my $collection = $dom->preceding_nodes;
395
8563f527 396Return a L<collection|/"COLLECTION METHODS"> containing all sibling nodes
397before this node as L<DOM::Tiny> objects.
d6512b50 398
399 # "A"
400 $dom->parse('A<!-- B --><p>C</p>')->at('p')->preceding_nodes->first->content;
401
402=head2 prepend
403
404 $dom = $dom->prepend('<p>I ♥ DOM::Tiny!</p>');
405
406Prepend HTML/XML fragment to this node.
407
408 # "<div><h1>Test</h1><h2>123</h2></div>"
409 $dom->parse('<div><h2>123</h2></div>')
410 ->at('h2')->prepend('<h1>Test</h1>')->root;
411
412 # "<p>Test 123</p>"
413 $dom->parse('<p>123</p>')
414 ->at('p')->child_nodes->first->prepend('Test ')->root;
415
416=head2 prepend_content
417
418 $dom = $dom->prepend_content('<p>I ♥ DOM::Tiny!</p>');
419
420Prepend HTML/XML fragment (for C<root> and C<tag> nodes) or raw content to this
421node's content.
422
423 # "<div><h2>Test123</h2></div>"
424 $dom->parse('<div><h2>123</h2></div>')
425 ->at('h2')->prepend_content('Test')->root;
426
427 # "<!-- Test 123 --><br>"
428 $dom->parse('<!-- 123 --><br>')
429 ->child_nodes->first->prepend_content(' Test')->root;
430
431 # "<p><i>123</i>Test</p>"
432 $dom->parse('<p>Test</p>')->at('p')->prepend_content('<i>123</i>')->root;
433
434=head2 previous
435
436 my $sibling = $dom->previous;
437
438Return L<DOM::Tiny> object for previous sibling element or C<undef> if there
439are no more siblings.
440
441 # "<h1>Test</h1>"
442 $dom->parse('<div><h1>Test</h1><h2>123</h2></div>')->at('h2')->previous;
443
444=head2 previous_node
445
446 my $sibling = $dom->previous_node;
447
448Return L<DOM::Tiny> object for previous sibling node or C<undef> if there are
449no more siblings.
450
451 # "123"
452 $dom->parse('<p>123<!-- Test --><b>456</b></p>')
453 ->at('b')->previous_node->previous_node;
454
455 # " Test "
456 $dom->parse('<p>123<!-- Test --><b>456</b></p>')
457 ->at('b')->previous_node->content;
458
459=head2 remove
460
461 my $parent = $dom->remove;
462
463Remove this node and return L</"root"> (for C<root> nodes) or L</"parent">.
464
465 # "<div></div>"
466 $dom->parse('<div><h1>Test</h1></div>')->at('h1')->remove;
467
468 # "<p><b>456</b></p>"
469 $dom->parse('<p>123<b>456</b></p>')
470 ->at('p')->child_nodes->first->remove->root;
471
472=head2 replace
473
474 my $parent = $dom->replace('<div>I ♥ DOM::Tiny!</div>');
475
476Replace this node with HTML/XML fragment and return L</"root"> (for C<root>
477nodes) or L</"parent">.
478
479 # "<div><h2>123</h2></div>"
480 $dom->parse('<div><h1>Test</h1></div>')->at('h1')->replace('<h2>123</h2>');
481
482 # "<p><b>123</b></p>"
483 $dom->parse('<p>Test</p>')
484 ->at('p')->child_nodes->[0]->replace('<b>123</b>')->root;
485
486=head2 root
487
488 my $root = $dom->root;
489
490Return L<DOM::Tiny> object for C<root> node.
491
492=head2 strip
493
494 my $parent = $dom->strip;
495
496Remove this element while preserving its content and return L</"parent">.
497
498 # "<div>Test</div>"
499 $dom->parse('<div><h1>Test</h1></div>')->at('h1')->strip;
500
501=head2 tag
502
503 my $tag = $dom->tag;
504 $dom = $dom->tag('div');
505
506This element's tag name.
507
508 # List tag names of child elements
509 say $dom->children->map('tag')->join("\n");
510
511=head2 tap
512
513 $dom = $dom->tap(sub {...});
514
e99ef07d 515Equivalent to L<Mojo::Base/"tap">.
d6512b50 516
517=head2 text
518
519 my $trimmed = $dom->text;
520 my $untrimmed = $dom->text(0);
521
522Extract text content from this element only (not including child elements),
523smart whitespace trimming is enabled by default.
524
525 # "foo baz"
526 $dom->parse("<div>foo\n<p>bar</p>baz\n</div>")->at('div')->text;
527
528 # "foo\nbaz\n"
529 $dom->parse("<div>foo\n<p>bar</p>baz\n</div>")->at('div')->text(0);
530
531=head2 to_string
532
533 my $str = $dom->to_string;
534
535Render this node and its content to HTML/XML.
536
537 # "<b>Test</b>"
538 $dom->parse('<div><b>Test</b></div>')->at('div b')->to_string;
539
540=head2 tree
541
542 my $tree = $dom->tree;
543 $dom = $dom->tree(['root']);
544
545Document Object Model. Note that this structure should only be used very
546carefully since it is very dynamic.
547
548=head2 type
549
550 my $type = $dom->type;
551
552This node's type, usually C<cdata>, C<comment>, C<doctype>, C<pi>, C<raw>,
553C<root>, C<tag> or C<text>.
554
555 # "cdata"
556 $dom->parse('<![CDATA[Test]]>')->child_nodes->first->type;
557
558 # "comment"
559 $dom->parse('<!-- Test -->')->child_nodes->first->type;
560
561 # "doctype"
562 $dom->parse('<!DOCTYPE html>')->child_nodes->first->type;
563
564 # "pi"
565 $dom->parse('<?xml version="1.0"?>')->child_nodes->first->type;
566
567 # "raw"
568 $dom->parse('<title>Test</title>')->at('title')->child_nodes->first->type;
569
570 # "root"
571 $dom->parse('<p>Test</p>')->type;
572
573 # "tag"
574 $dom->parse('<p>Test</p>')->at('p')->type;
575
576 # "text"
577 $dom->parse('<p>Test</p>')->at('p')->child_nodes->first->type;
578
579=head2 val
580
581 my $value = $dom->val;
582
583Extract value from form element (such as C<button>, C<input>, C<option>,
584C<select> and C<textarea>) or return C<undef> if this element has no value. In
585the case of C<select> with C<multiple> attribute, find C<option> elements with
586C<selected> attribute and return an array reference with all values or C<undef>
587if none could be found.
588
589 # "a"
590 $dom->parse('<input name="test" value="a">')->at('input')->val;
591
592 # "b"
593 $dom->parse('<textarea>b</textarea>')->at('textarea')->val;
594
595 # "c"
596 $dom->parse('<option value="c">Test</option>')->at('option')->val;
597
598 # "d"
599 $dom->parse('<select><option selected>d</option></select>')
600 ->at('select')->val;
601
602 # "e"
603 $dom->parse('<select multiple><option selected>e</option></select>')
604 ->at('select')->val->[0];
605
606=head2 wrap
607
608 $dom = $dom->wrap('<div></div>');
609
610Wrap HTML/XML fragment around this node, placing it as the last child of the
611first innermost element.
612
613 # "<p>123<b>Test</b></p>"
614 $dom->parse('<b>Test</b>')->at('b')->wrap('<p>123</p>')->root;
615
616 # "<div><p><b>Test</b></p>123</div>"
617 $dom->parse('<b>Test</b>')->at('b')->wrap('<div><p></p>123</div>')->root;
618
619 # "<p><b>Test</b></p><p>123</p>"
620 $dom->parse('<b>Test</b>')->at('b')->wrap('<p></p><p>123</p>')->root;
621
622 # "<p><b>Test</b></p>"
623 $dom->parse('<p>Test</p>')->at('p')->child_nodes->first->wrap('<b>')->root;
624
625=head2 wrap_content
626
627 $dom = $dom->wrap_content('<div></div>');
628
629Wrap HTML/XML fragment around this node's content, placing it as the last
630children of the first innermost element.
631
632 # "<p><b>123Test</b></p>"
633 $dom->parse('<p>Test<p>')->at('p')->wrap_content('<b>123</b>')->root;
634
635 # "<p><b>Test</b></p><p>123</p>"
636 $dom->parse('<b>Test</b>')->wrap_content('<p></p><p>123</p>');
637
638=head2 xml
639
640 my $bool = $dom->xml;
641 $dom = $dom->xml($bool);
642
643Disable HTML semantics in parser and activate case-sensitivity, defaults to
644auto detection based on processing instructions.
645
646=head1 OPERATORS
647
648L<DOM::Tiny> overloads the following operators.
649
650=head2 array
651
652 my @nodes = @$dom;
653
654Alias for L</"child_nodes">.
655
656 # "<!-- Test -->"
657 $dom->parse('<!-- Test --><b>123</b>')->[0];
658
659=head2 bool
660
661 my $bool = !!$dom;
662
663Always true.
664
665=head2 hash
666
667 my %attrs = %$dom;
668
669Alias for L</"attr">.
670
671 # "test"
672 $dom->parse('<div id="test">Test</div>')->at('div')->{id};
673
674=head2 stringify
675
676 my $str = "$dom";
677
678Alias for L</"to_string">.
679
78ba4051 680=head1 COLLECTION METHODS
681
682Some L<DOM::Tiny> methods return an array-based collection object, which can
683either be accessed directly as an array reference, or with the following
684methods.
685
686 # Chain methods
687 $collection->map(sub { ucfirst })->shuffle->each(sub {
688 my ($word, $num) = @_;
689 say "$num: $word";
690 });
691
692 # Access array directly to manipulate collection
693 $collection->[23] += 100;
694 say for @$collection;
695
696=head2 compact
697
698 my $new = $collection->compact;
699
700Create a new collection with all elements that are defined and not an empty
701string.
702
703 # $collection contains (0, 1, undef, 2, '', 3)
704 $collection->compact->join(', '); # "0, 1, 2, 3"
705
706=head2 each
707
708 my @elements = $collection->each;
709 $collection = $collection->each(sub {...});
710
711Evaluate callback for each element in collection or return all elements as a
712list if none has been provided. The element will be the first argument passed
713to the callback and is also available as C<$_>.
714
715 # Make a numbered list
716 $collection->each(sub {
717 my ($e, $num) = @_;
718 say "$num: $e";
719 });
720
721=head2 first
722
723 my $first = $collection->first;
724 my $first = $collection->first(qr/foo/);
725 my $first = $collection->first(sub {...});
726 my $first = $collection->first($method);
727 my $first = $collection->first($method, @args);
728
729Evaluate regular expression/callback for, or call method on, each element in
730collection and return the first one that matched the regular expression, or for
731which the callback/method returned true. The element will be the first argument
732passed to the callback and is also available as C<$_>.
733
734 # Longer version
735 my $first = $collection->first(sub { $_->$method(@args) });
736
737 # Find first value that contains the word "dom"
738 my $interesting = $collection->first(qr/dom/i);
739
740 # Find first value that is greater than 5
741 my $greater = $collection->first(sub { $_ > 5 });
742
743=head2 flatten
744
745 my $new = $collection->flatten;
746
747Flatten nested collections/arrays recursively and create a new collection with
748all elements.
749
750 # $collection contains (1, [2, [3, 4], 5, [6]], 7)
751 $collection->flatten->join(', '); # "1, 2, 3, 4, 5, 6, 7"
752
753=head2 grep
754
755 my $new = $collection->grep(qr/foo/);
756 my $new = $collection->grep(sub {...});
757 my $new = $collection->grep($method);
758 my $new = $collection->grep($method, @args);
759
760Evaluate regular expression/callback for, or call method on, each element in
761collection and create a new collection with all elements that matched the
762regular expression, or for which the callback/method returned true. The element
763will be the first argument passed to the callback and is also available as
764C<$_>.
765
766 # Longer version
767 my $new = $collection->grep(sub { $_->$method(@args) });
768
769 # Find all values that contain the word "dom"
770 my $interesting = $collection->grep(qr/dom/i);
771
772 # Find all values that are greater than 5
773 my $greater = $collection->grep(sub { $_ > 5 });
774
775=head2 join
776
777 my $stream = $collection->join;
778 my $stream = $collection->join("\n");
779
780Turn collection into string.
781
782 # Join all values with commas
783 $collection->join(', ');
784
785=head2 last
786
787 my $last = $collection->last;
788
789Return the last element in collection.
790
791=head2 map
792
793 my $new = $collection->map(sub {...});
794 my $new = $collection->map($method);
795 my $new = $collection->map($method, @args);
796
797Evaluate callback for, or call method on, each element in collection and create
798a new collection from the results. The element will be the first argument
799passed to the callback and is also available as C<$_>.
800
801 # Longer version
802 my $new = $collection->map(sub { $_->$method(@args) });
803
804 # Append the word "dom" to all values
805 my $domified = $collection->map(sub { $_ . 'dom' });
806
807=head2 reduce
808
809 my $result = $collection->reduce(sub {...});
810 my $result = $collection->reduce(sub {...}, $initial);
811
812Reduce elements in collection with callback, the first element will be used as
813initial value if none has been provided.
814
815 # Calculate the sum of all values
816 my $sum = $collection->reduce(sub { $a + $b });
817
818 # Count how often each value occurs in collection
819 my $hash = $collection->reduce(sub { $a->{$b}++; $a }, {});
820
821=head2 reverse
822
823 my $new = $collection->reverse;
824
825Create a new collection with all elements in reverse order.
826
827=head2 slice
828
829 my $new = $collection->slice(4 .. 7);
830
831Create a new collection with all selected elements.
832
833 # $collection contains ('A', 'B', 'C', 'D', 'E')
834 $collection->slice(1, 2, 4)->join(' '); # "B C E"
835
836=head2 shuffle
837
838 my $new = $collection->shuffle;
839
840Create a new collection with all elements in random order.
841
842=head2 size
843
844 my $size = $collection->size;
845
846Number of elements in collection.
847
848=head2 sort
849
850 my $new = $collection->sort;
851 my $new = $collection->sort(sub {...});
852
853Sort elements based on return value of callback and create a new collection
854from the results.
855
856 # Sort values case-insensitive
857 my $case_insensitive = $collection->sort(sub { uc($a) cmp uc($b) });
858
859=head2 tap
860
861 $collection = $collection->tap(sub {...});
862
863Equivalent to L<Mojo::Base/"tap">.
864
865=head2 to_array
866
867 my $array = $collection->to_array;
868
869Turn collection into array reference.
870
871=head2 uniq
872
873 my $new = $collection->uniq;
874 my $new = $collection->uniq(sub {...});
875 my $new = $collection->uniq($method);
876 my $new = $collection->uniq($method, @args);
877
878Create a new collection without duplicate elements, using the string
879representation of either the elements or the return value of the
880callback/method.
881
882 # Longer version
883 my $new = $collection->uniq(sub { $_->$method(@args) });
884
885 # $collection contains ('foo', 'bar', 'bar', 'baz')
886 $collection->uniq->join(' '); # "foo bar baz"
887
888 # $collection contains ([1, 2], [2, 1], [3, 2])
889 $collection->uniq(sub{ $_->[1] })->to_array; # "[[1, 2], [2, 1]]"
890
d6512b50 891=head1 BUGS
892
893Report any issues on the public bugtracker.
894
895=head1 AUTHOR
896
897Dan Book <dbook@cpan.org>
898
899=head1 COPYRIGHT AND LICENSE
900
901This software is Copyright (c) 2015 by Dan Book.
902
903This is free software, licensed under:
904
905 The Artistic License 2.0 (GPL Compatible)
906
907=head1 SEE ALSO
908
909L<Mojo::DOM>, L<XML::LibXML>, L<XML::Twig>, L<HTML::TreeBuilder>, L<XML::Smart>
910
911=cut