Commit | Line | Data |
d6512b50 |
1 | use strict; |
2 | use warnings; |
3 | use utf8; |
4 | use Test::More; |
5 | use DOM::Tiny; |
dbff35d4 |
6 | use JSON::PP (); |
d6512b50 |
7 | |
8 | # Empty |
9 | is(DOM::Tiny->new, '', 'right result'); |
10 | is(DOM::Tiny->new(''), '', 'right result'); |
11 | is(DOM::Tiny->new->parse(''), '', 'right result'); |
12 | is(DOM::Tiny->new->at('p'), undef, 'no result'); |
13 | is(DOM::Tiny->new->append_content(''), '', 'right result'); |
14 | is(DOM::Tiny->new->all_text, '', 'right result'); |
15 | |
16 | # Simple (basics) |
17 | my $dom |
18 | = DOM::Tiny->new('<div><div FOO="0" id="a">A</div><div id="b">B</div></div>'); |
19 | is $dom->at('#b')->text, 'B', 'right text'; |
20 | my @div; |
21 | push @div, $dom->find('div[id]')->map('text')->each; |
22 | is_deeply \@div, [qw(A B)], 'found all div elements with id'; |
23 | @div = (); |
24 | $dom->find('div[id]')->each(sub { push @div, $_->text }); |
25 | is_deeply \@div, [qw(A B)], 'found all div elements with id'; |
26 | is $dom->at('#a')->attr('foo'), 0, 'right attribute'; |
27 | is $dom->at('#a')->attr->{foo}, 0, 'right attribute'; |
28 | is "$dom", '<div><div foo="0" id="a">A</div><div id="b">B</div></div>', |
29 | 'right result'; |
30 | |
31 | # Tap into method chain |
32 | $dom = DOM::Tiny->new->parse('<div id="a">A</div><div id="b">B</div>'); |
33 | is_deeply [$dom->find('[id]')->map(attr => 'id')->each], [qw(a b)], |
34 | 'right result'; |
35 | is $dom->tap(sub { $_->at('#b')->remove }), '<div id="a">A</div>', |
36 | 'right result'; |
37 | |
38 | # Build tree from scratch |
39 | is(DOM::Tiny->new->append_content('<p>')->at('p')->append_content('0')->text, |
40 | '0', 'right text'); |
41 | |
42 | # Simple nesting with healing (tree structure) |
43 | $dom = DOM::Tiny->new(<<EOF); |
44 | <foo><bar a="b<c">ju<baz a23>s<bazz />t</bar>works</foo> |
45 | EOF |
46 | is $dom->tree->[0], 'root', 'right type'; |
47 | is $dom->tree->[1][0], 'tag', 'right type'; |
48 | is $dom->tree->[1][1], 'foo', 'right tag'; |
49 | is_deeply $dom->tree->[1][2], {}, 'empty attributes'; |
50 | is $dom->tree->[1][3], $dom->tree, 'right parent'; |
51 | is $dom->tree->[1][4][0], 'tag', 'right type'; |
52 | is $dom->tree->[1][4][1], 'bar', 'right tag'; |
53 | is_deeply $dom->tree->[1][4][2], {a => 'b<c'}, 'right attributes'; |
54 | is $dom->tree->[1][4][3], $dom->tree->[1], 'right parent'; |
55 | is $dom->tree->[1][4][4][0], 'text', 'right type'; |
56 | is $dom->tree->[1][4][4][1], 'ju', 'right text'; |
57 | is $dom->tree->[1][4][4][2], $dom->tree->[1][4], 'right parent'; |
58 | is $dom->tree->[1][4][5][0], 'tag', 'right type'; |
59 | is $dom->tree->[1][4][5][1], 'baz', 'right tag'; |
60 | is_deeply $dom->tree->[1][4][5][2], {a23 => undef}, 'right attributes'; |
61 | is $dom->tree->[1][4][5][3], $dom->tree->[1][4], 'right parent'; |
62 | is $dom->tree->[1][4][5][4][0], 'text', 'right type'; |
63 | is $dom->tree->[1][4][5][4][1], 's', 'right text'; |
64 | is $dom->tree->[1][4][5][4][2], $dom->tree->[1][4][5], 'right parent'; |
65 | is $dom->tree->[1][4][5][5][0], 'tag', 'right type'; |
66 | is $dom->tree->[1][4][5][5][1], 'bazz', 'right tag'; |
67 | is_deeply $dom->tree->[1][4][5][5][2], {}, 'empty attributes'; |
68 | is $dom->tree->[1][4][5][5][3], $dom->tree->[1][4][5], 'right parent'; |
69 | is $dom->tree->[1][4][5][6][0], 'text', 'right type'; |
70 | is $dom->tree->[1][4][5][6][1], 't', 'right text'; |
71 | is $dom->tree->[1][4][5][6][2], $dom->tree->[1][4][5], 'right parent'; |
72 | is $dom->tree->[1][5][0], 'text', 'right type'; |
73 | is $dom->tree->[1][5][1], 'works', 'right text'; |
74 | is $dom->tree->[1][5][2], $dom->tree->[1], 'right parent'; |
75 | is "$dom", <<EOF, 'right result'; |
76 | <foo><bar a="b<c">ju<baz a23>s<bazz></bazz>t</baz></bar>works</foo> |
77 | EOF |
78 | |
79 | # Select based on parent |
80 | $dom = DOM::Tiny->new(<<EOF); |
81 | <body> |
82 | <div>test1</div> |
83 | <div><div>test2</div></div> |
84 | <body> |
85 | EOF |
86 | is $dom->find('body > div')->[0]->text, 'test1', 'right text'; |
87 | is $dom->find('body > div')->[1]->text, '', 'no content'; |
88 | is $dom->find('body > div')->[2], undef, 'no result'; |
89 | is $dom->find('body > div')->size, 2, 'right number of elements'; |
90 | is $dom->find('body > div > div')->[0]->text, 'test2', 'right text'; |
91 | is $dom->find('body > div > div')->[1], undef, 'no result'; |
92 | is $dom->find('body > div > div')->size, 1, 'right number of elements'; |
93 | |
94 | # A bit of everything (basic navigation) |
95 | $dom = DOM::Tiny->new->parse(<<EOF); |
96 | <!doctype foo> |
97 | <foo bar="ba<z"> |
98 | test |
99 | <simple class="working">easy</simple> |
100 | <test foo="bar" id="test" /> |
101 | <!-- lala --> |
102 | works well |
103 | <![CDATA[ yada yada]]> |
104 | <?boom lalalala ?> |
105 | <a little bit broken> |
106 | < very broken |
107 | <br /> |
108 | more text |
109 | </foo> |
110 | EOF |
111 | ok !$dom->xml, 'XML mode not detected'; |
112 | is $dom->tag, undef, 'no tag'; |
113 | is $dom->attr('foo'), undef, 'no attribute'; |
114 | is $dom->attr(foo => 'bar')->attr('foo'), undef, 'no attribute'; |
115 | is $dom->tree->[1][0], 'doctype', 'right type'; |
116 | is $dom->tree->[1][1], ' foo', 'right doctype'; |
117 | is "$dom", <<EOF, 'right result'; |
118 | <!DOCTYPE foo> |
119 | <foo bar="ba<z"> |
120 | test |
121 | <simple class="working">easy</simple> |
122 | <test foo="bar" id="test"></test> |
123 | <!-- lala --> |
124 | works well |
125 | <![CDATA[ yada yada]]> |
126 | <?boom lalalala ?> |
127 | <a bit broken little> |
128 | < very broken |
129 | <br> |
130 | more text |
131 | </a></foo> |
132 | EOF |
133 | my $simple = $dom->at('foo simple.working[class^="wor"]'); |
134 | is $simple->parent->all_text, |
135 | 'test easy works well yada yada < very broken more text', 'right text'; |
136 | is $simple->tag, 'simple', 'right tag'; |
137 | is $simple->attr('class'), 'working', 'right class attribute'; |
138 | is $simple->text, 'easy', 'right text'; |
139 | is $simple->parent->tag, 'foo', 'right parent tag'; |
140 | is $simple->parent->attr->{bar}, 'ba<z', 'right parent attribute'; |
141 | is $simple->parent->children->[1]->tag, 'test', 'right sibling'; |
142 | is $simple->to_string, '<simple class="working">easy</simple>', |
143 | 'stringified right'; |
144 | $simple->parent->attr(bar => 'baz')->attr({this => 'works', too => 'yea'}); |
145 | is $simple->parent->attr('bar'), 'baz', 'right parent attribute'; |
146 | is $simple->parent->attr('this'), 'works', 'right parent attribute'; |
147 | is $simple->parent->attr('too'), 'yea', 'right parent attribute'; |
148 | is $dom->at('test#test')->tag, 'test', 'right tag'; |
149 | is $dom->at('[class$="ing"]')->tag, 'simple', 'right tag'; |
150 | is $dom->at('[class="working"]')->tag, 'simple', 'right tag'; |
151 | is $dom->at('[class$=ing]')->tag, 'simple', 'right tag'; |
152 | is $dom->at('[class=working][class]')->tag, 'simple', 'right tag'; |
153 | is $dom->at('foo > simple')->next->tag, 'test', 'right tag'; |
154 | is $dom->at('foo > simple')->next->next->tag, 'a', 'right tag'; |
155 | is $dom->at('foo > test')->previous->tag, 'simple', 'right tag'; |
156 | is $dom->next, undef, 'no siblings'; |
157 | is $dom->previous, undef, 'no siblings'; |
158 | is $dom->at('foo > a')->next, undef, 'no next sibling'; |
159 | is $dom->at('foo > simple')->previous, undef, 'no previous sibling'; |
160 | is_deeply [$dom->at('simple')->ancestors->map('tag')->each], ['foo'], |
161 | 'right results'; |
162 | ok !$dom->at('simple')->ancestors->first->xml, 'XML mode not active'; |
163 | |
164 | # Nodes |
165 | $dom = DOM::Tiny->new( |
166 | '<!DOCTYPE before><p>test<![CDATA[123]]><!-- 456 --></p><?after?>'); |
167 | is $dom->at('p')->preceding_nodes->first->content, ' before', 'right content'; |
168 | is $dom->at('p')->preceding_nodes->size, 1, 'right number of nodes'; |
169 | is $dom->at('p')->child_nodes->last->preceding_nodes->first->content, 'test', |
170 | 'right content'; |
171 | is $dom->at('p')->child_nodes->last->preceding_nodes->last->content, '123', |
172 | 'right content'; |
173 | is $dom->at('p')->child_nodes->last->preceding_nodes->size, 2, |
174 | 'right number of nodes'; |
175 | is $dom->preceding_nodes->size, 0, 'no preceding nodes'; |
176 | is $dom->at('p')->following_nodes->first->content, 'after', 'right content'; |
177 | is $dom->at('p')->following_nodes->size, 1, 'right number of nodes'; |
178 | is $dom->child_nodes->first->following_nodes->first->tag, 'p', 'right tag'; |
179 | is $dom->child_nodes->first->following_nodes->last->content, 'after', |
180 | 'right content'; |
181 | is $dom->child_nodes->first->following_nodes->size, 2, 'right number of nodes'; |
182 | is $dom->following_nodes->size, 0, 'no following nodes'; |
183 | is $dom->at('p')->previous_node->content, ' before', 'right content'; |
184 | is $dom->at('p')->previous_node->previous_node, undef, 'no more siblings'; |
185 | is $dom->at('p')->next_node->content, 'after', 'right content'; |
186 | is $dom->at('p')->next_node->next_node, undef, 'no more siblings'; |
187 | is $dom->at('p')->child_nodes->last->previous_node->previous_node->content, |
188 | 'test', 'right content'; |
189 | is $dom->at('p')->child_nodes->first->next_node->next_node->content, ' 456 ', |
190 | 'right content'; |
191 | is $dom->descendant_nodes->[0]->type, 'doctype', 'right type'; |
192 | is $dom->descendant_nodes->[0]->content, ' before', 'right content'; |
193 | is $dom->descendant_nodes->[0], '<!DOCTYPE before>', 'right content'; |
194 | is $dom->descendant_nodes->[1]->tag, 'p', 'right tag'; |
195 | is $dom->descendant_nodes->[2]->type, 'text', 'right type'; |
196 | is $dom->descendant_nodes->[2]->content, 'test', 'right content'; |
197 | is $dom->descendant_nodes->[5]->type, 'pi', 'right type'; |
198 | is $dom->descendant_nodes->[5]->content, 'after', 'right content'; |
199 | is $dom->at('p')->descendant_nodes->[0]->type, 'text', 'right type'; |
200 | is $dom->at('p')->descendant_nodes->[0]->content, 'test', 'right type'; |
201 | is $dom->at('p')->descendant_nodes->last->type, 'comment', 'right type'; |
202 | is $dom->at('p')->descendant_nodes->last->content, ' 456 ', 'right type'; |
203 | is $dom->child_nodes->[1]->child_nodes->first->parent->tag, 'p', 'right tag'; |
204 | is $dom->child_nodes->[1]->child_nodes->first->content, 'test', 'right content'; |
205 | is $dom->child_nodes->[1]->child_nodes->first, 'test', 'right content'; |
206 | is $dom->at('p')->child_nodes->first->type, 'text', 'right type'; |
207 | is $dom->at('p')->child_nodes->first->remove->tag, 'p', 'right tag'; |
208 | is $dom->at('p')->child_nodes->first->type, 'cdata', 'right type'; |
209 | is $dom->at('p')->child_nodes->first->content, '123', 'right content'; |
210 | is $dom->at('p')->child_nodes->[1]->type, 'comment', 'right type'; |
211 | is $dom->at('p')->child_nodes->[1]->content, ' 456 ', 'right content'; |
212 | is $dom->[0]->type, 'doctype', 'right type'; |
213 | is $dom->[0]->content, ' before', 'right content'; |
214 | is $dom->child_nodes->[2]->type, 'pi', 'right type'; |
215 | is $dom->child_nodes->[2]->content, 'after', 'right content'; |
216 | is $dom->child_nodes->first->content(' again')->content, ' again', |
217 | 'right content'; |
218 | is $dom->child_nodes->grep(sub { $_->type eq 'pi' })->map('remove') |
219 | ->first->type, 'root', 'right type'; |
220 | is "$dom", '<!DOCTYPE again><p><![CDATA[123]]><!-- 456 --></p>', 'right result'; |
221 | |
222 | # Modify nodes |
223 | $dom = DOM::Tiny->new('<script>la<la>la</script>'); |
224 | is $dom->at('script')->type, 'tag', 'right type'; |
225 | is $dom->at('script')->[0]->type, 'raw', 'right type'; |
226 | is $dom->at('script')->[0]->content, 'la<la>la', 'right content'; |
227 | is "$dom", '<script>la<la>la</script>', 'right result'; |
228 | is $dom->at('script')->child_nodes->first->replace('a<b>c</b>1<b>d</b>')->tag, |
229 | 'script', 'right tag'; |
230 | is "$dom", '<script>a<b>c</b>1<b>d</b></script>', 'right result'; |
231 | is $dom->at('b')->child_nodes->first->append('e')->content, 'c', |
232 | 'right content'; |
233 | is $dom->at('b')->child_nodes->first->prepend('f')->type, 'text', 'right type'; |
234 | is "$dom", '<script>a<b>fce</b>1<b>d</b></script>', 'right result'; |
235 | is $dom->at('script')->child_nodes->first->following->first->tag, 'b', |
236 | 'right tag'; |
237 | is $dom->at('script')->child_nodes->first->next->content, 'fce', |
238 | 'right content'; |
239 | is $dom->at('script')->child_nodes->first->previous, undef, 'no siblings'; |
240 | is $dom->at('script')->child_nodes->[2]->previous->content, 'fce', |
241 | 'right content'; |
242 | is $dom->at('b')->child_nodes->[1]->next, undef, 'no siblings'; |
243 | is $dom->at('script')->child_nodes->first->wrap('<i>:)</i>')->root, |
244 | '<script><i>:)a</i><b>fce</b>1<b>d</b></script>', 'right result'; |
245 | is $dom->at('i')->child_nodes->first->wrap_content('<b></b>')->root, |
c7cad649 |
246 | '<script><i>:)a</i><b>fce</b>1<b>d</b></script>', 'no changes'; |
247 | is $dom->at('i')->child_nodes->first->wrap('<b></b>')->root, |
d6512b50 |
248 | '<script><i><b>:)</b>a</i><b>fce</b>1<b>d</b></script>', 'right result'; |
249 | is $dom->at('b')->child_nodes->first->ancestors->map('tag')->join(','), |
250 | 'b,i,script', 'right result'; |
251 | is $dom->at('b')->child_nodes->first->append_content('g')->content, ':)g', |
252 | 'right content'; |
253 | is $dom->at('b')->child_nodes->first->prepend_content('h')->content, 'h:)g', |
254 | 'right content'; |
255 | is "$dom", '<script><i><b>h:)g</b>a</i><b>fce</b>1<b>d</b></script>', |
256 | 'right result'; |
257 | is $dom->at('script > b:last-of-type')->append('<!--y-->') |
258 | ->following_nodes->first->content, 'y', 'right content'; |
259 | is $dom->at('i')->prepend('z')->preceding_nodes->first->content, 'z', |
260 | 'right content'; |
261 | is $dom->at('i')->following->last->text, 'd', 'right text'; |
262 | is $dom->at('i')->following->size, 2, 'right number of following elements'; |
263 | is $dom->at('i')->following('b:last-of-type')->first->text, 'd', 'right text'; |
264 | is $dom->at('i')->following('b:last-of-type')->size, 1, |
265 | 'right number of following elements'; |
266 | is $dom->following->size, 0, 'no following elements'; |
267 | is $dom->at('script > b:last-of-type')->preceding->first->tag, 'i', 'right tag'; |
268 | is $dom->at('script > b:last-of-type')->preceding->size, 2, |
269 | 'right number of preceding elements'; |
270 | is $dom->at('script > b:last-of-type')->preceding('b')->first->tag, 'b', |
271 | 'right tag'; |
272 | is $dom->at('script > b:last-of-type')->preceding('b')->size, 1, |
273 | 'right number of preceding elements'; |
274 | is $dom->preceding->size, 0, 'no preceding elements'; |
275 | is "$dom", '<script>z<i><b>h:)g</b>a</i><b>fce</b>1<b>d</b><!--y--></script>', |
276 | 'right result'; |
277 | |
278 | # XML nodes |
279 | $dom = DOM::Tiny->new->xml(1)->parse('<b>test<image /></b>'); |
280 | ok $dom->at('b')->child_nodes->first->xml, 'XML mode active'; |
281 | ok $dom->at('b')->child_nodes->first->replace('<br>')->child_nodes->first->xml, |
282 | 'XML mode active'; |
283 | is "$dom", '<b><br /><image /></b>', 'right result'; |
284 | |
285 | # Treating nodes as elements |
286 | $dom = DOM::Tiny->new('foo<b>bar</b>baz'); |
287 | is $dom->child_nodes->first->child_nodes->size, 0, 'no nodes'; |
288 | is $dom->child_nodes->first->descendant_nodes->size, 0, 'no nodes'; |
289 | is $dom->child_nodes->first->children->size, 0, 'no children'; |
290 | is $dom->child_nodes->first->strip->parent, 'foo<b>bar</b>baz', 'no changes'; |
291 | is $dom->child_nodes->first->at('b'), undef, 'no result'; |
292 | is $dom->child_nodes->first->find('*')->size, 0, 'no results'; |
293 | ok !$dom->child_nodes->first->matches('*'), 'no match'; |
294 | is_deeply $dom->child_nodes->first->attr, {}, 'no attributes'; |
295 | is $dom->child_nodes->first->namespace, undef, 'no namespace'; |
296 | is $dom->child_nodes->first->tag, undef, 'no tag'; |
297 | is $dom->child_nodes->first->text, '', 'no text'; |
298 | is $dom->child_nodes->first->all_text, '', 'no text'; |
299 | |
300 | # Class and ID |
301 | $dom = DOM::Tiny->new('<div id="id" class="class">a</div>'); |
302 | is $dom->at('div#id.class')->text, 'a', 'right text'; |
303 | |
304 | # Deep nesting (parent combinator) |
305 | $dom = DOM::Tiny->new(<<EOF); |
306 | <html> |
307 | <head> |
308 | <title>Foo</title> |
309 | </head> |
310 | <body> |
311 | <div id="container"> |
312 | <div id="header"> |
313 | <div id="logo">Hello World</div> |
314 | <div id="buttons"> |
315 | <p id="foo">Foo</p> |
316 | </div> |
317 | </div> |
318 | <form> |
319 | <div id="buttons"> |
320 | <p id="bar">Bar</p> |
321 | </div> |
322 | </form> |
323 | <div id="content">More stuff</div> |
324 | </div> |
325 | </body> |
326 | </html> |
327 | EOF |
328 | my $p = $dom->find('body > #container > div p[id]'); |
329 | is $p->[0]->attr('id'), 'foo', 'right id attribute'; |
330 | is $p->[1], undef, 'no second result'; |
331 | is $p->size, 1, 'right number of elements'; |
332 | my @p; |
333 | @div = (); |
334 | $dom->find('div')->each(sub { push @div, $_->attr('id') }); |
335 | $dom->find('p')->each(sub { push @p, $_->attr('id') }); |
336 | is_deeply \@p, [qw(foo bar)], 'found all p elements'; |
337 | my $ids = [qw(container header logo buttons buttons content)]; |
338 | is_deeply \@div, $ids, 'found all div elements'; |
339 | is_deeply [$dom->at('p')->ancestors->map('tag')->each], |
340 | [qw(div div div body html)], 'right results'; |
341 | is_deeply [$dom->at('html')->ancestors->each], [], 'no results'; |
342 | is_deeply [$dom->ancestors->each], [], 'no results'; |
343 | |
344 | # Script tag |
345 | $dom = DOM::Tiny->new(<<EOF); |
346 | <script charset="utf-8">alert('lalala');</script> |
347 | EOF |
348 | is $dom->at('script')->text, "alert('lalala');", 'right script content'; |
349 | |
350 | # HTML5 (unquoted values) |
351 | $dom = DOM::Tiny->new( |
352 | '<div id = test foo ="bar" class=tset bar=/baz/ baz=//>works</div>'); |
353 | is $dom->at('#test')->text, 'works', 'right text'; |
354 | is $dom->at('div')->text, 'works', 'right text'; |
355 | is $dom->at('[foo=bar][foo="bar"]')->text, 'works', 'right text'; |
356 | is $dom->at('[foo="ba"]'), undef, 'no result'; |
357 | is $dom->at('[foo=bar]')->text, 'works', 'right text'; |
358 | is $dom->at('[foo=ba]'), undef, 'no result'; |
359 | is $dom->at('.tset')->text, 'works', 'right text'; |
360 | is $dom->at('[bar=/baz/]')->text, 'works', 'right text'; |
361 | is $dom->at('[baz=//]')->text, 'works', 'right text'; |
362 | |
363 | # HTML1 (single quotes, uppercase tags and whitespace in attributes) |
364 | $dom = DOM::Tiny->new(q{<DIV id = 'test' foo ='bar' class= "tset">works</DIV>}); |
365 | is $dom->at('#test')->text, 'works', 'right text'; |
366 | is $dom->at('div')->text, 'works', 'right text'; |
367 | is $dom->at('[foo="bar"]')->text, 'works', 'right text'; |
368 | is $dom->at('[foo="ba"]'), undef, 'no result'; |
369 | is $dom->at('[foo=bar]')->text, 'works', 'right text'; |
370 | is $dom->at('[foo=ba]'), undef, 'no result'; |
371 | is $dom->at('.tset')->text, 'works', 'right text'; |
372 | |
373 | # Already decoded Unicode snowman and quotes in selector |
374 | $dom = DOM::Tiny->new('<div id="snow'm"an">☃</div>'); |
375 | is $dom->at('[id="snow\'m\"an"]')->text, '☃', 'right text'; |
376 | is $dom->at('[id="snow\'m\22 an"]')->text, '☃', 'right text'; |
377 | is $dom->at('[id="snow\'m\000022an"]')->text, '☃', 'right text'; |
378 | is $dom->at('[id="snow\'m\22an"]'), undef, 'no result'; |
379 | is $dom->at('[id="snow\'m\21 an"]'), undef, 'no result'; |
380 | is $dom->at('[id="snow\'m\000021an"]'), undef, 'no result'; |
381 | is $dom->at('[id="snow\'m\000021 an"]'), undef, 'no result'; |
382 | is $dom->at("[id='snow\\'m\"an']")->text, '☃', 'right text'; |
383 | is $dom->at("[id='snow\\27m\"an']")->text, '☃', 'right text'; |
384 | |
385 | # Unicode and escaped selectors |
386 | my $html |
387 | = '<html><div id="☃x">Snowman</div><div class="x ♥">Heart</div></html>'; |
388 | $dom = DOM::Tiny->new($html); |
389 | is $dom->at("#\\\n\\002603x")->text, 'Snowman', 'right text'; |
390 | is $dom->at('#\\2603 x')->text, 'Snowman', 'right text'; |
391 | is $dom->at("#\\\n\\2603 x")->text, 'Snowman', 'right text'; |
392 | is $dom->at(qq{[id="\\\n\\2603 x"]})->text, 'Snowman', 'right text'; |
393 | is $dom->at(qq{[id="\\\n\\002603x"]})->text, 'Snowman', 'right text'; |
394 | is $dom->at(qq{[id="\\\\2603 x"]})->text, 'Snowman', 'right text'; |
395 | is $dom->at("html #\\\n\\002603x")->text, 'Snowman', 'right text'; |
396 | is $dom->at('html #\\2603 x')->text, 'Snowman', 'right text'; |
397 | is $dom->at("html #\\\n\\2603 x")->text, 'Snowman', 'right text'; |
398 | is $dom->at(qq{html [id="\\\n\\2603 x"]})->text, 'Snowman', 'right text'; |
399 | is $dom->at(qq{html [id="\\\n\\002603x"]})->text, 'Snowman', 'right text'; |
400 | is $dom->at(qq{html [id="\\\\2603 x"]})->text, 'Snowman', 'right text'; |
401 | is $dom->at('#☃x')->text, 'Snowman', 'right text'; |
402 | is $dom->at('div#☃x')->text, 'Snowman', 'right text'; |
403 | is $dom->at('html div#☃x')->text, 'Snowman', 'right text'; |
404 | is $dom->at('[id^="☃"]')->text, 'Snowman', 'right text'; |
405 | is $dom->at('div[id^="☃"]')->text, 'Snowman', 'right text'; |
406 | is $dom->at('html div[id^="☃"]')->text, 'Snowman', 'right text'; |
407 | is $dom->at('html > div[id^="☃"]')->text, 'Snowman', 'right text'; |
408 | is $dom->at('[id^=☃]')->text, 'Snowman', 'right text'; |
409 | is $dom->at('div[id^=☃]')->text, 'Snowman', 'right text'; |
410 | is $dom->at('html div[id^=☃]')->text, 'Snowman', 'right text'; |
411 | is $dom->at('html > div[id^=☃]')->text, 'Snowman', 'right text'; |
412 | is $dom->at(".\\\n\\002665")->text, 'Heart', 'right text'; |
413 | is $dom->at('.\\2665')->text, 'Heart', 'right text'; |
414 | is $dom->at("html .\\\n\\002665")->text, 'Heart', 'right text'; |
415 | is $dom->at('html .\\2665')->text, 'Heart', 'right text'; |
416 | is $dom->at(qq{html [class\$="\\\n\\002665"]})->text, 'Heart', 'right text'; |
417 | is $dom->at(qq{html [class\$="\\2665"]})->text, 'Heart', 'right text'; |
418 | is $dom->at(qq{[class\$="\\\n\\002665"]})->text, 'Heart', 'right text'; |
419 | is $dom->at(qq{[class\$="\\2665"]})->text, 'Heart', 'right text'; |
420 | is $dom->at('.x')->text, 'Heart', 'right text'; |
421 | is $dom->at('html .x')->text, 'Heart', 'right text'; |
422 | is $dom->at('.♥')->text, 'Heart', 'right text'; |
423 | is $dom->at('html .♥')->text, 'Heart', 'right text'; |
424 | is $dom->at('div.♥')->text, 'Heart', 'right text'; |
425 | is $dom->at('html div.♥')->text, 'Heart', 'right text'; |
426 | is $dom->at('[class$="♥"]')->text, 'Heart', 'right text'; |
427 | is $dom->at('div[class$="♥"]')->text, 'Heart', 'right text'; |
428 | is $dom->at('html div[class$="♥"]')->text, 'Heart', 'right text'; |
429 | is $dom->at('html > div[class$="♥"]')->text, 'Heart', 'right text'; |
430 | is $dom->at('[class$=♥]')->text, 'Heart', 'right text'; |
431 | is $dom->at('div[class$=♥]')->text, 'Heart', 'right text'; |
432 | is $dom->at('html div[class$=♥]')->text, 'Heart', 'right text'; |
433 | is $dom->at('html > div[class$=♥]')->text, 'Heart', 'right text'; |
434 | is $dom->at('[class~="♥"]')->text, 'Heart', 'right text'; |
435 | is $dom->at('div[class~="♥"]')->text, 'Heart', 'right text'; |
436 | is $dom->at('html div[class~="♥"]')->text, 'Heart', 'right text'; |
437 | is $dom->at('html > div[class~="♥"]')->text, 'Heart', 'right text'; |
438 | is $dom->at('[class~=♥]')->text, 'Heart', 'right text'; |
439 | is $dom->at('div[class~=♥]')->text, 'Heart', 'right text'; |
440 | is $dom->at('html div[class~=♥]')->text, 'Heart', 'right text'; |
441 | is $dom->at('html > div[class~=♥]')->text, 'Heart', 'right text'; |
442 | is $dom->at('[class~="x"]')->text, 'Heart', 'right text'; |
443 | is $dom->at('div[class~="x"]')->text, 'Heart', 'right text'; |
444 | is $dom->at('html div[class~="x"]')->text, 'Heart', 'right text'; |
445 | is $dom->at('html > div[class~="x"]')->text, 'Heart', 'right text'; |
446 | is $dom->at('[class~=x]')->text, 'Heart', 'right text'; |
447 | is $dom->at('div[class~=x]')->text, 'Heart', 'right text'; |
448 | is $dom->at('html div[class~=x]')->text, 'Heart', 'right text'; |
449 | is $dom->at('html > div[class~=x]')->text, 'Heart', 'right text'; |
450 | is $dom->at('html'), $html, 'right result'; |
451 | is $dom->at('#☃x')->parent, $html, 'right result'; |
452 | is $dom->at('#☃x')->root, $html, 'right result'; |
453 | is $dom->children('html')->first, $html, 'right result'; |
454 | is $dom->to_string, $html, 'right result'; |
455 | is $dom->content, $html, 'right result'; |
456 | |
457 | # Looks remotely like HTML |
458 | $dom = DOM::Tiny->new( |
459 | '<!DOCTYPE H "-/W/D HT 4/E">☃<title class=test>♥</title>☃'); |
460 | is $dom->at('title')->text, '♥', 'right text'; |
461 | is $dom->at('*')->text, '♥', 'right text'; |
462 | is $dom->at('.test')->text, '♥', 'right text'; |
463 | |
464 | # Replace elements |
465 | $dom = DOM::Tiny->new('<div>foo<p>lalala</p>bar</div>'); |
466 | is $dom->at('p')->replace('<foo>bar</foo>'), '<div>foo<foo>bar</foo>bar</div>', |
467 | 'right result'; |
468 | is "$dom", '<div>foo<foo>bar</foo>bar</div>', 'right result'; |
469 | $dom->at('foo')->replace(DOM::Tiny->new('text')); |
470 | is "$dom", '<div>footextbar</div>', 'right result'; |
471 | $dom = DOM::Tiny->new('<div>foo</div><div>bar</div>'); |
472 | $dom->find('div')->each(sub { shift->replace('<p>test</p>') }); |
473 | is "$dom", '<p>test</p><p>test</p>', 'right result'; |
474 | $dom = DOM::Tiny->new('<div>foo<p>lalala</p>bar</div>'); |
475 | is $dom->replace('♥'), '♥', 'right result'; |
476 | is "$dom", '♥', 'right result'; |
477 | $dom->replace('<div>foo<p>lalala</p>bar</div>'); |
478 | is "$dom", '<div>foo<p>lalala</p>bar</div>', 'right result'; |
479 | is $dom->at('p')->replace(''), '<div>foobar</div>', 'right result'; |
480 | is "$dom", '<div>foobar</div>', 'right result'; |
481 | is $dom->replace(''), '', 'no result'; |
482 | is "$dom", '', 'no result'; |
483 | $dom->replace('<div>foo<p>lalala</p>bar</div>'); |
484 | is "$dom", '<div>foo<p>lalala</p>bar</div>', 'right result'; |
485 | $dom->find('p')->map(replace => ''); |
486 | is "$dom", '<div>foobar</div>', 'right result'; |
487 | $dom = DOM::Tiny->new('<div>♥</div>'); |
488 | $dom->at('div')->content('☃'); |
489 | is "$dom", '<div>☃</div>', 'right result'; |
490 | $dom = DOM::Tiny->new('<div>♥</div>'); |
491 | $dom->at('div')->content("\x{2603}"); |
492 | is $dom->to_string, '<div>☃</div>', 'right result'; |
493 | is $dom->at('div')->replace('<p>♥</p>')->root, '<p>♥</p>', 'right result'; |
494 | is $dom->to_string, '<p>♥</p>', 'right result'; |
495 | is $dom->replace('<b>whatever</b>')->root, '<b>whatever</b>', 'right result'; |
496 | is $dom->to_string, '<b>whatever</b>', 'right result'; |
497 | $dom->at('b')->prepend('<p>foo</p>')->append('<p>bar</p>'); |
498 | is "$dom", '<p>foo</p><b>whatever</b><p>bar</p>', 'right result'; |
499 | is $dom->find('p')->map('remove')->first->root->at('b')->text, 'whatever', |
500 | 'right result'; |
501 | is "$dom", '<b>whatever</b>', 'right result'; |
502 | is $dom->at('b')->strip, 'whatever', 'right result'; |
503 | is $dom->strip, 'whatever', 'right result'; |
504 | is $dom->remove, '', 'right result'; |
505 | $dom->replace('A<div>B<p>C<b>D<i><u>E</u></i>F</b>G</p><div>H</div></div>I'); |
506 | is $dom->find(':not(div):not(i):not(u)')->map('strip')->first->root, |
507 | 'A<div>BCD<i><u>E</u></i>FG<div>H</div></div>I', 'right result'; |
508 | is $dom->at('i')->to_string, '<i><u>E</u></i>', 'right result'; |
509 | $dom = DOM::Tiny->new('<div><div>A</div><div>B</div>C</div>'); |
510 | is $dom->at('div')->at('div')->text, 'A', 'right text'; |
511 | $dom->at('div')->find('div')->map('strip'); |
512 | is "$dom", '<div>ABC</div>', 'right result'; |
513 | |
514 | # Replace element content |
515 | $dom = DOM::Tiny->new('<div>foo<p>lalala</p>bar</div>'); |
516 | is $dom->at('p')->content('bar'), '<p>bar</p>', 'right result'; |
517 | is "$dom", '<div>foo<p>bar</p>bar</div>', 'right result'; |
518 | $dom->at('p')->content(DOM::Tiny->new('text')); |
519 | is "$dom", '<div>foo<p>text</p>bar</div>', 'right result'; |
520 | $dom = DOM::Tiny->new('<div>foo</div><div>bar</div>'); |
521 | $dom->find('div')->each(sub { shift->content('<p>test</p>') }); |
522 | is "$dom", '<div><p>test</p></div><div><p>test</p></div>', 'right result'; |
523 | $dom->find('p')->each(sub { shift->content('') }); |
524 | is "$dom", '<div><p></p></div><div><p></p></div>', 'right result'; |
525 | $dom = DOM::Tiny->new('<div><p id="☃" /></div>'); |
526 | $dom->at('#☃')->content('♥'); |
527 | is "$dom", '<div><p id="☃">♥</p></div>', 'right result'; |
528 | $dom = DOM::Tiny->new('<div>foo<p>lalala</p>bar</div>'); |
529 | $dom->content('♥'); |
530 | is "$dom", '♥', 'right result'; |
531 | is $dom->content('<div>foo<p>lalala</p>bar</div>'), |
532 | '<div>foo<p>lalala</p>bar</div>', 'right result'; |
533 | is "$dom", '<div>foo<p>lalala</p>bar</div>', 'right result'; |
534 | is $dom->content(''), '', 'no result'; |
535 | is "$dom", '', 'no result'; |
536 | $dom->content('<div>foo<p>lalala</p>bar</div>'); |
537 | is "$dom", '<div>foo<p>lalala</p>bar</div>', 'right result'; |
538 | is $dom->at('p')->content(''), '<p></p>', 'right result'; |
539 | |
540 | # Mixed search and tree walk |
541 | $dom = DOM::Tiny->new(<<EOF); |
542 | <table> |
543 | <tr> |
544 | <td>text1</td> |
545 | <td>text2</td> |
546 | </tr> |
547 | </table> |
548 | EOF |
549 | my @data; |
550 | for my $tr ($dom->find('table tr')->each) { |
551 | for my $td (@{$tr->children}) { |
552 | push @data, $td->tag, $td->all_text; |
553 | } |
554 | } |
555 | is $data[0], 'td', 'right tag'; |
556 | is $data[1], 'text1', 'right text'; |
557 | is $data[2], 'td', 'right tag'; |
558 | is $data[3], 'text2', 'right text'; |
559 | is $data[4], undef, 'no tag'; |
560 | |
561 | # RSS |
562 | $dom = DOM::Tiny->new(<<EOF); |
563 | <?xml version="1.0" encoding="UTF-8"?> |
564 | <rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"> |
565 | <channel> |
566 | <title>Test Blog</title> |
567 | <link>http://blog.example.com</link> |
568 | <description>lalala</description> |
569 | <generator>DOM::Tiny</generator> |
570 | <item> |
571 | <pubDate>Mon, 12 Jul 2010 20:42:00</pubDate> |
572 | <title>Works!</title> |
573 | <link>http://blog.example.com/test</link> |
574 | <guid>http://blog.example.com/test</guid> |
575 | <description> |
576 | <![CDATA[<p>trololololo>]]> |
577 | </description> |
578 | <my:extension foo:id="works"> |
579 | <![CDATA[ |
580 | [awesome]] |
581 | ]]> |
582 | </my:extension> |
583 | </item> |
584 | </channel> |
585 | </rss> |
586 | EOF |
587 | ok $dom->xml, 'XML mode detected'; |
588 | is $dom->find('rss')->[0]->attr('version'), '2.0', 'right version'; |
589 | is_deeply [$dom->at('title')->ancestors->map('tag')->each], [qw(channel rss)], |
590 | 'right results'; |
591 | is $dom->at('extension')->attr('foo:id'), 'works', 'right id'; |
592 | like $dom->at('#works')->text, qr/\[awesome\]\]/, 'right text'; |
593 | like $dom->at('[id="works"]')->text, qr/\[awesome\]\]/, 'right text'; |
594 | is $dom->find('description')->[1]->text, '<p>trololololo>', 'right text'; |
595 | is $dom->at('pubDate')->text, 'Mon, 12 Jul 2010 20:42:00', 'right text'; |
596 | like $dom->at('[id*="ork"]')->text, qr/\[awesome\]\]/, 'right text'; |
597 | like $dom->at('[id*="orks"]')->text, qr/\[awesome\]\]/, 'right text'; |
598 | like $dom->at('[id*="work"]')->text, qr/\[awesome\]\]/, 'right text'; |
599 | like $dom->at('[id*="or"]')->text, qr/\[awesome\]\]/, 'right text'; |
600 | ok $dom->at('rss')->xml, 'XML mode active'; |
601 | ok $dom->at('extension')->parent->xml, 'XML mode active'; |
602 | ok $dom->at('extension')->root->xml, 'XML mode active'; |
603 | ok $dom->children('rss')->first->xml, 'XML mode active'; |
604 | ok $dom->at('title')->ancestors->first->xml, 'XML mode active'; |
605 | |
606 | # Namespace |
607 | $dom = DOM::Tiny->new(<<EOF); |
608 | <?xml version="1.0"?> |
609 | <bk:book xmlns='uri:default-ns' |
610 | xmlns:bk='uri:book-ns' |
611 | xmlns:isbn='uri:isbn-ns'> |
612 | <bk:title>Programming Perl</bk:title> |
613 | <comment>rocks!</comment> |
614 | <nons xmlns=''> |
615 | <section>Nothing</section> |
616 | </nons> |
617 | <meta xmlns='uri:meta-ns'> |
618 | <isbn:number>978-0596000271</isbn:number> |
619 | </meta> |
620 | </bk:book> |
621 | EOF |
622 | ok $dom->xml, 'XML mode detected'; |
623 | is $dom->namespace, undef, 'no namespace'; |
624 | is $dom->at('book comment')->namespace, 'uri:default-ns', 'right namespace'; |
625 | is $dom->at('book comment')->text, 'rocks!', 'right text'; |
626 | is $dom->at('book nons section')->namespace, '', 'no namespace'; |
627 | is $dom->at('book nons section')->text, 'Nothing', 'right text'; |
628 | is $dom->at('book meta number')->namespace, 'uri:isbn-ns', 'right namespace'; |
629 | is $dom->at('book meta number')->text, '978-0596000271', 'right text'; |
630 | is $dom->children('bk\:book')->first->{xmlns}, 'uri:default-ns', |
631 | 'right attribute'; |
632 | is $dom->children('book')->first->{xmlns}, 'uri:default-ns', 'right attribute'; |
633 | is $dom->children('k\:book')->first, undef, 'no result'; |
634 | is $dom->children('ook')->first, undef, 'no result'; |
635 | is $dom->at('k\:book'), undef, 'no result'; |
636 | is $dom->at('ook'), undef, 'no result'; |
637 | is $dom->at('[xmlns\:bk]')->{'xmlns:bk'}, 'uri:book-ns', 'right attribute'; |
638 | is $dom->at('[bk]')->{'xmlns:bk'}, 'uri:book-ns', 'right attribute'; |
639 | is $dom->at('[bk]')->attr('xmlns:bk'), 'uri:book-ns', 'right attribute'; |
640 | is $dom->at('[bk]')->attr('s:bk'), undef, 'no attribute'; |
641 | is $dom->at('[bk]')->attr('bk'), undef, 'no attribute'; |
642 | is $dom->at('[bk]')->attr('k'), undef, 'no attribute'; |
643 | is $dom->at('[s\:bk]'), undef, 'no result'; |
644 | is $dom->at('[k]'), undef, 'no result'; |
645 | is $dom->at('number')->ancestors('meta')->first->{xmlns}, 'uri:meta-ns', |
646 | 'right attribute'; |
647 | ok $dom->at('nons')->matches('book > nons'), 'element did match'; |
648 | ok !$dom->at('title')->matches('book > nons > section'), |
649 | 'element did not match'; |
650 | |
651 | # Dots |
652 | $dom = DOM::Tiny->new(<<EOF); |
653 | <?xml version="1.0"?> |
654 | <foo xmlns:foo.bar="uri:first"> |
655 | <bar xmlns:fooxbar="uri:second"> |
656 | <foo.bar:baz>First</fooxbar:baz> |
657 | <fooxbar:ya.da>Second</foo.bar:ya.da> |
658 | </bar> |
659 | </foo> |
660 | EOF |
661 | is $dom->at('foo bar baz')->text, 'First', 'right text'; |
662 | is $dom->at('baz')->namespace, 'uri:first', 'right namespace'; |
663 | is $dom->at('foo bar ya\.da')->text, 'Second', 'right text'; |
664 | is $dom->at('ya\.da')->namespace, 'uri:second', 'right namespace'; |
665 | is $dom->at('foo')->namespace, undef, 'no namespace'; |
666 | is $dom->at('[xml\.s]'), undef, 'no result'; |
667 | is $dom->at('b\.z'), undef, 'no result'; |
668 | |
669 | # Yadis |
670 | $dom = DOM::Tiny->new(<<'EOF'); |
671 | <?xml version="1.0" encoding="UTF-8"?> |
672 | <XRDS xmlns="xri://$xrds"> |
673 | <XRD xmlns="xri://$xrd*($v*2.0)"> |
674 | <Service> |
675 | <Type>http://o.r.g/sso/2.0</Type> |
676 | </Service> |
677 | <Service> |
678 | <Type>http://o.r.g/sso/1.0</Type> |
679 | </Service> |
680 | </XRD> |
681 | </XRDS> |
682 | EOF |
683 | ok $dom->xml, 'XML mode detected'; |
684 | is $dom->at('XRDS')->namespace, 'xri://$xrds', 'right namespace'; |
685 | is $dom->at('XRD')->namespace, 'xri://$xrd*($v*2.0)', 'right namespace'; |
686 | my $s = $dom->find('XRDS XRD Service'); |
687 | is $s->[0]->at('Type')->text, 'http://o.r.g/sso/2.0', 'right text'; |
688 | is $s->[0]->namespace, 'xri://$xrd*($v*2.0)', 'right namespace'; |
689 | is $s->[1]->at('Type')->text, 'http://o.r.g/sso/1.0', 'right text'; |
690 | is $s->[1]->namespace, 'xri://$xrd*($v*2.0)', 'right namespace'; |
691 | is $s->[2], undef, 'no result'; |
692 | is $s->size, 2, 'right number of elements'; |
693 | |
694 | # Yadis (roundtrip with namespace) |
695 | my $yadis = <<'EOF'; |
696 | <?xml version="1.0" encoding="UTF-8"?> |
697 | <xrds:XRDS xmlns="xri://$xrd*($v*2.0)" xmlns:xrds="xri://$xrds"> |
698 | <XRD> |
699 | <Service> |
700 | <Type>http://o.r.g/sso/3.0</Type> |
701 | </Service> |
702 | <xrds:Service> |
703 | <Type>http://o.r.g/sso/4.0</Type> |
704 | </xrds:Service> |
705 | </XRD> |
706 | <XRD> |
707 | <Service> |
708 | <Type test="23">http://o.r.g/sso/2.0</Type> |
709 | </Service> |
710 | <Service> |
711 | <Type Test="23" test="24">http://o.r.g/sso/1.0</Type> |
712 | </Service> |
713 | </XRD> |
714 | </xrds:XRDS> |
715 | EOF |
716 | $dom = DOM::Tiny->new($yadis); |
717 | ok $dom->xml, 'XML mode detected'; |
718 | is $dom->at('XRDS')->namespace, 'xri://$xrds', 'right namespace'; |
719 | is $dom->at('XRD')->namespace, 'xri://$xrd*($v*2.0)', 'right namespace'; |
720 | $s = $dom->find('XRDS XRD Service'); |
721 | is $s->[0]->at('Type')->text, 'http://o.r.g/sso/3.0', 'right text'; |
722 | is $s->[0]->namespace, 'xri://$xrd*($v*2.0)', 'right namespace'; |
723 | is $s->[1]->at('Type')->text, 'http://o.r.g/sso/4.0', 'right text'; |
724 | is $s->[1]->namespace, 'xri://$xrds', 'right namespace'; |
725 | is $s->[2]->at('Type')->text, 'http://o.r.g/sso/2.0', 'right text'; |
726 | is $s->[2]->namespace, 'xri://$xrd*($v*2.0)', 'right namespace'; |
727 | is $s->[3]->at('Type')->text, 'http://o.r.g/sso/1.0', 'right text'; |
728 | is $s->[3]->namespace, 'xri://$xrd*($v*2.0)', 'right namespace'; |
729 | is $s->[4], undef, 'no result'; |
730 | is $s->size, 4, 'right number of elements'; |
731 | is $dom->at('[Test="23"]')->text, 'http://o.r.g/sso/1.0', 'right text'; |
732 | is $dom->at('[test="23"]')->text, 'http://o.r.g/sso/2.0', 'right text'; |
733 | is $dom->find('xrds\:Service > Type')->[0]->text, 'http://o.r.g/sso/4.0', |
734 | 'right text'; |
735 | is $dom->find('xrds\:Service > Type')->[1], undef, 'no result'; |
736 | is $dom->find('xrds\3AService > Type')->[0]->text, 'http://o.r.g/sso/4.0', |
737 | 'right text'; |
738 | is $dom->find('xrds\3AService > Type')->[1], undef, 'no result'; |
739 | is $dom->find('xrds\3A Service > Type')->[0]->text, 'http://o.r.g/sso/4.0', |
740 | 'right text'; |
741 | is $dom->find('xrds\3A Service > Type')->[1], undef, 'no result'; |
742 | is $dom->find('xrds\00003AService > Type')->[0]->text, 'http://o.r.g/sso/4.0', |
743 | 'right text'; |
744 | is $dom->find('xrds\00003AService > Type')->[1], undef, 'no result'; |
745 | is $dom->find('xrds\00003A Service > Type')->[0]->text, 'http://o.r.g/sso/4.0', |
746 | 'right text'; |
747 | is $dom->find('xrds\00003A Service > Type')->[1], undef, 'no result'; |
748 | is "$dom", $yadis, 'successful roundtrip'; |
749 | |
750 | # Result and iterator order |
751 | $dom = DOM::Tiny->new('<a><b>1</b></a><b>2</b><b>3</b>'); |
752 | my @numbers; |
753 | $dom->find('b')->each(sub { push @numbers, pop, shift->text }); |
754 | is_deeply \@numbers, [1, 1, 2, 2, 3, 3], 'right order'; |
755 | |
756 | # Attributes on multiple lines |
757 | $dom = DOM::Tiny->new("<div test=23 id='a' \n class='x' foo=bar />"); |
758 | is $dom->at('div.x')->attr('test'), 23, 'right attribute'; |
759 | is $dom->at('[foo="bar"]')->attr('class'), 'x', 'right attribute'; |
760 | is $dom->at('div')->attr(baz => undef)->root->to_string, |
761 | '<div baz class="x" foo="bar" id="a" test="23"></div>', 'right result'; |
762 | |
763 | # Markup characters in attribute values |
764 | $dom = DOM::Tiny->new(qq{<div id="<a>" \n test='='>Test<div id='><' /></div>}); |
765 | is $dom->at('div[id="<a>"]')->attr->{test}, '=', 'right attribute'; |
766 | is $dom->at('[id="<a>"]')->text, 'Test', 'right text'; |
767 | is $dom->at('[id="><"]')->attr->{id}, '><', 'right attribute'; |
768 | |
769 | # Empty attributes |
770 | $dom = DOM::Tiny->new(qq{<div test="" test2='' />}); |
771 | is $dom->at('div')->attr->{test}, '', 'empty attribute value'; |
772 | is $dom->at('div')->attr->{test2}, '', 'empty attribute value'; |
773 | is $dom->at('[test]')->tag, 'div', 'right tag'; |
774 | is $dom->at('[test2]')->tag, 'div', 'right tag'; |
775 | is $dom->at('[test3]'), undef, 'no result'; |
776 | is $dom->at('[test=""]')->tag, 'div', 'right tag'; |
777 | is $dom->at('[test2=""]')->tag, 'div', 'right tag'; |
778 | is $dom->at('[test3=""]'), undef, 'no result'; |
779 | |
927f1351 |
780 | # Multi-line attribute |
781 | $dom = DOM::Tiny->new(qq{<div class="line1\nline2" />}); |
782 | is $dom->at('div')->attr->{class}, "line1\nline2", 'multi-line attribute value'; |
783 | is $dom->at('.line1')->tag, 'div', 'right tag'; |
784 | is $dom->at('.line2')->tag, 'div', 'right tag'; |
785 | is $dom->at('.line3'), undef, 'no result'; |
d6512b50 |
786 | |
787 | # Whitespaces before closing bracket |
788 | $dom = DOM::Tiny->new('<div >content</div>'); |
789 | ok $dom->at('div'), 'tag found'; |
790 | is $dom->at('div')->text, 'content', 'right text'; |
791 | is $dom->at('div')->content, 'content', 'right text'; |
792 | |
793 | # Class with hyphen |
794 | $dom = DOM::Tiny->new('<div class="a">A</div><div class="a-1">A1</div>'); |
795 | @div = (); |
796 | $dom->find('.a')->each(sub { push @div, shift->text }); |
797 | is_deeply \@div, ['A'], 'found first element only'; |
798 | @div = (); |
799 | $dom->find('.a-1')->each(sub { push @div, shift->text }); |
800 | is_deeply \@div, ['A1'], 'found last element only'; |
801 | |
802 | # Defined but false text |
803 | $dom = DOM::Tiny->new( |
804 | '<div><div id="a">A</div><div id="b">B</div></div><div id="0">0</div>'); |
805 | @div = (); |
806 | $dom->find('div[id]')->each(sub { push @div, shift->text }); |
807 | is_deeply \@div, [qw(A B 0)], 'found all div elements with id'; |
808 | |
809 | # Empty tags |
810 | $dom = DOM::Tiny->new('<hr /><br/><br id="br"/><br />'); |
811 | is "$dom", '<hr><br><br id="br"><br>', 'right result'; |
812 | is $dom->at('br')->content, '', 'empty result'; |
813 | |
814 | # Inner XML |
815 | $dom = DOM::Tiny->new('<a>xxx<x>x</x>xxx</a>'); |
816 | is $dom->at('a')->content, 'xxx<x>x</x>xxx', 'right result'; |
817 | is $dom->content, '<a>xxx<x>x</x>xxx</a>', 'right result'; |
818 | |
819 | # Multiple selectors |
820 | $dom = DOM::Tiny->new( |
821 | '<div id="a">A</div><div id="b">B</div><div id="c">C</div><p>D</p>'); |
822 | @div = (); |
823 | $dom->find('p, div')->each(sub { push @div, shift->text }); |
824 | is_deeply \@div, [qw(A B C D)], 'found all elements'; |
825 | @div = (); |
826 | $dom->find('#a, #c')->each(sub { push @div, shift->text }); |
827 | is_deeply \@div, [qw(A C)], 'found all div elements with the right ids'; |
828 | @div = (); |
829 | $dom->find('div#a, div#b')->each(sub { push @div, shift->text }); |
830 | is_deeply \@div, [qw(A B)], 'found all div elements with the right ids'; |
831 | @div = (); |
832 | $dom->find('div[id="a"], div[id="c"]')->each(sub { push @div, shift->text }); |
833 | is_deeply \@div, [qw(A C)], 'found all div elements with the right ids'; |
834 | $dom = DOM::Tiny->new( |
835 | '<div id="☃">A</div><div id="b">B</div><div id="♥x">C</div>'); |
836 | @div = (); |
837 | $dom->find('#☃, #♥x')->each(sub { push @div, shift->text }); |
838 | is_deeply \@div, [qw(A C)], 'found all div elements with the right ids'; |
839 | @div = (); |
840 | $dom->find('div#☃, div#b')->each(sub { push @div, shift->text }); |
841 | is_deeply \@div, [qw(A B)], 'found all div elements with the right ids'; |
842 | @div = (); |
843 | $dom->find('div[id="☃"], div[id="♥x"]') |
844 | ->each(sub { push @div, shift->text }); |
845 | is_deeply \@div, [qw(A C)], 'found all div elements with the right ids'; |
846 | |
847 | # Multiple attributes |
848 | $dom = DOM::Tiny->new(<<EOF); |
849 | <div foo="bar" bar="baz">A</div> |
850 | <div foo="bar">B</div> |
851 | <div foo="bar" bar="baz">C</div> |
852 | <div foo="baz" bar="baz">D</div> |
853 | EOF |
854 | @div = (); |
855 | $dom->find('div[foo="bar"][bar="baz"]')->each(sub { push @div, shift->text }); |
856 | is_deeply \@div, [qw(A C)], 'found all div elements with the right atributes'; |
857 | @div = (); |
858 | $dom->find('div[foo^="b"][foo$="r"]')->each(sub { push @div, shift->text }); |
859 | is_deeply \@div, [qw(A B C)], 'found all div elements with the right atributes'; |
860 | is $dom->at('[foo="bar"]')->previous, undef, 'no previous sibling'; |
861 | is $dom->at('[foo="bar"]')->next->text, 'B', 'right text'; |
862 | is $dom->at('[foo="bar"]')->next->previous->text, 'A', 'right text'; |
863 | is $dom->at('[foo="bar"]')->next->next->next->next, undef, 'no next sibling'; |
864 | |
865 | # Pseudo-classes |
866 | $dom = DOM::Tiny->new(<<EOF); |
867 | <form action="/foo"> |
868 | <input type="text" name="user" value="test" /> |
869 | <input type="checkbox" checked="checked" name="groovy"> |
870 | <select name="a"> |
871 | <option value="b">b</option> |
872 | <optgroup label="c"> |
873 | <option value="d">d</option> |
874 | <option selected="selected" value="e">E</option> |
875 | <option value="f">f</option> |
876 | </optgroup> |
877 | <option value="g">g</option> |
878 | <option selected value="h">H</option> |
879 | </select> |
880 | <input type="submit" value="Ok!" /> |
881 | <input type="checkbox" checked name="I"> |
882 | <p id="content">test 123</p> |
883 | <p id="no_content"><? test ?><!-- 123 --></p> |
884 | </form> |
885 | EOF |
886 | is $dom->find(':root')->[0]->tag, 'form', 'right tag'; |
887 | is $dom->find('*:root')->[0]->tag, 'form', 'right tag'; |
888 | is $dom->find('form:root')->[0]->tag, 'form', 'right tag'; |
889 | is $dom->find(':root')->[1], undef, 'no result'; |
890 | is $dom->find(':checked')->[0]->attr->{name}, 'groovy', 'right name'; |
891 | is $dom->find('option:checked')->[0]->attr->{value}, 'e', 'right value'; |
892 | is $dom->find(':checked')->[1]->text, 'E', 'right text'; |
893 | is $dom->find('*:checked')->[1]->text, 'E', 'right text'; |
894 | is $dom->find(':checked')->[2]->text, 'H', 'right name'; |
895 | is $dom->find(':checked')->[3]->attr->{name}, 'I', 'right name'; |
896 | is $dom->find(':checked')->[4], undef, 'no result'; |
897 | is $dom->find('option[selected]')->[0]->attr->{value}, 'e', 'right value'; |
898 | is $dom->find('option[selected]')->[1]->text, 'H', 'right text'; |
899 | is $dom->find('option[selected]')->[2], undef, 'no result'; |
900 | is $dom->find(':checked[value="e"]')->[0]->text, 'E', 'right text'; |
901 | is $dom->find('*:checked[value="e"]')->[0]->text, 'E', 'right text'; |
902 | is $dom->find('option:checked[value="e"]')->[0]->text, 'E', 'right text'; |
903 | is $dom->at('optgroup option:checked[value="e"]')->text, 'E', 'right text'; |
904 | is $dom->at('select option:checked[value="e"]')->text, 'E', 'right text'; |
905 | is $dom->at('select :checked[value="e"]')->text, 'E', 'right text'; |
906 | is $dom->at('optgroup > :checked[value="e"]')->text, 'E', 'right text'; |
907 | is $dom->at('select *:checked[value="e"]')->text, 'E', 'right text'; |
908 | is $dom->at('optgroup > *:checked[value="e"]')->text, 'E', 'right text'; |
909 | is $dom->find(':checked[value="e"]')->[1], undef, 'no result'; |
910 | is $dom->find(':empty')->[0]->attr->{name}, 'user', 'right name'; |
911 | is $dom->find('input:empty')->[0]->attr->{name}, 'user', 'right name'; |
912 | is $dom->at(':empty[type^="ch"]')->attr->{name}, 'groovy', 'right name'; |
913 | is $dom->at('p')->attr->{id}, 'content', 'right attribute'; |
914 | is $dom->at('p:empty')->attr->{id}, 'no_content', 'right attribute'; |
915 | |
916 | # More pseudo-classes |
917 | $dom = DOM::Tiny->new(<<EOF); |
918 | <ul> |
919 | <li>A</li> |
920 | <li>B</li> |
921 | <li>C</li> |
922 | <li>D</li> |
923 | <li>E</li> |
924 | <li>F</li> |
925 | <li>G</li> |
926 | <li>H</li> |
927 | </ul> |
928 | EOF |
929 | my @li; |
930 | $dom->find('li:nth-child(odd)')->each(sub { push @li, shift->text }); |
931 | is_deeply \@li, [qw(A C E G)], 'found all odd li elements'; |
932 | @li = (); |
933 | $dom->find('li:NTH-CHILD(ODD)')->each(sub { push @li, shift->text }); |
934 | is_deeply \@li, [qw(A C E G)], 'found all odd li elements'; |
935 | @li = (); |
936 | $dom->find('li:nth-last-child(odd)')->each(sub { push @li, shift->text }); |
937 | is_deeply \@li, [qw(B D F H)], 'found all odd li elements'; |
938 | is $dom->find(':nth-child(odd)')->[0]->tag, 'ul', 'right tag'; |
939 | is $dom->find(':nth-child(odd)')->[1]->text, 'A', 'right text'; |
940 | is $dom->find(':nth-child(1)')->[0]->tag, 'ul', 'right tag'; |
941 | is $dom->find(':nth-child(1)')->[1]->text, 'A', 'right text'; |
942 | is $dom->find(':nth-last-child(odd)')->[0]->tag, 'ul', 'right tag'; |
943 | is $dom->find(':nth-last-child(odd)')->last->text, 'H', 'right text'; |
944 | is $dom->find(':nth-last-child(1)')->[0]->tag, 'ul', 'right tag'; |
945 | is $dom->find(':nth-last-child(1)')->[1]->text, 'H', 'right text'; |
946 | @li = (); |
947 | $dom->find('li:nth-child(2n+1)')->each(sub { push @li, shift->text }); |
948 | is_deeply \@li, [qw(A C E G)], 'found all odd li elements'; |
949 | @li = (); |
950 | $dom->find('li:nth-child(2n + 1)')->each(sub { push @li, shift->text }); |
951 | is_deeply \@li, [qw(A C E G)], 'found all odd li elements'; |
952 | @li = (); |
953 | $dom->find('li:nth-last-child(2n+1)')->each(sub { push @li, shift->text }); |
954 | is_deeply \@li, [qw(B D F H)], 'found all odd li elements'; |
955 | @li = (); |
956 | $dom->find('li:nth-child(even)')->each(sub { push @li, shift->text }); |
957 | is_deeply \@li, [qw(B D F H)], 'found all even li elements'; |
958 | @li = (); |
959 | $dom->find('li:NTH-CHILD(EVEN)')->each(sub { push @li, shift->text }); |
960 | is_deeply \@li, [qw(B D F H)], 'found all even li elements'; |
961 | @li = (); |
962 | $dom->find('li:nth-last-child( even )')->each(sub { push @li, shift->text }); |
963 | is_deeply \@li, [qw(A C E G)], 'found all even li elements'; |
964 | @li = (); |
965 | $dom->find('li:nth-child(2n+2)')->each(sub { push @li, shift->text }); |
966 | is_deeply \@li, [qw(B D F H)], 'found all even li elements'; |
967 | @li = (); |
968 | $dom->find('li:nTh-chILd(2N+2)')->each(sub { push @li, shift->text }); |
969 | is_deeply \@li, [qw(B D F H)], 'found all even li elements'; |
970 | @li = (); |
971 | $dom->find('li:nth-child( 2n + 2 )')->each(sub { push @li, shift->text }); |
972 | is_deeply \@li, [qw(B D F H)], 'found all even li elements'; |
973 | @li = (); |
974 | $dom->find('li:nth-last-child(2n+2)')->each(sub { push @li, shift->text }); |
975 | is_deeply \@li, [qw(A C E G)], 'found all even li elements'; |
976 | @li = (); |
977 | $dom->find('li:nth-child(4n+1)')->each(sub { push @li, shift->text }); |
978 | is_deeply \@li, [qw(A E)], 'found the right li elements'; |
979 | @li = (); |
980 | $dom->find('li:nth-last-child(4n+1)')->each(sub { push @li, shift->text }); |
981 | is_deeply \@li, [qw(D H)], 'found the right li elements'; |
982 | @li = (); |
983 | $dom->find('li:nth-child(4n+4)')->each(sub { push @li, shift->text }); |
eb9737f2 |
984 | is_deeply \@li, [qw(D H)], 'found the right li elements'; |
d6512b50 |
985 | @li = (); |
986 | $dom->find('li:nth-last-child(4n+4)')->each(sub { push @li, shift->text }); |
eb9737f2 |
987 | is_deeply \@li, [qw(A E)], 'found the right li elements'; |
d6512b50 |
988 | @li = (); |
989 | $dom->find('li:nth-child(4n)')->each(sub { push @li, shift->text }); |
eb9737f2 |
990 | is_deeply \@li, [qw(D H)], 'found the right li elements'; |
d6512b50 |
991 | @li = (); |
992 | $dom->find('li:nth-child( 4n )')->each(sub { push @li, shift->text }); |
eb9737f2 |
993 | is_deeply \@li, [qw(D H)], 'found the right li elements'; |
d6512b50 |
994 | @li = (); |
995 | $dom->find('li:nth-last-child(4n)')->each(sub { push @li, shift->text }); |
eb9737f2 |
996 | is_deeply \@li, [qw(A E)], 'found the right li elements'; |
d6512b50 |
997 | @li = (); |
998 | $dom->find('li:nth-child(5n-2)')->each(sub { push @li, shift->text }); |
eb9737f2 |
999 | is_deeply \@li, [qw(C H)], 'found the right li elements'; |
d6512b50 |
1000 | @li = (); |
1001 | $dom->find('li:nth-child( 5n - 2 )')->each(sub { push @li, shift->text }); |
eb9737f2 |
1002 | is_deeply \@li, [qw(C H)], 'found the right li elements'; |
d6512b50 |
1003 | @li = (); |
1004 | $dom->find('li:nth-last-child(5n-2)')->each(sub { push @li, shift->text }); |
eb9737f2 |
1005 | is_deeply \@li, [qw(A F)], 'found the right li elements'; |
d6512b50 |
1006 | @li = (); |
1007 | $dom->find('li:nth-child(-n+3)')->each(sub { push @li, shift->text }); |
1008 | is_deeply \@li, [qw(A B C)], 'found first three li elements'; |
1009 | @li = (); |
1010 | $dom->find('li:nth-child( -n + 3 )')->each(sub { push @li, shift->text }); |
1011 | is_deeply \@li, [qw(A B C)], 'found first three li elements'; |
1012 | @li = (); |
1013 | $dom->find('li:nth-last-child(-n+3)')->each(sub { push @li, shift->text }); |
1014 | is_deeply \@li, [qw(F G H)], 'found last three li elements'; |
1015 | @li = (); |
1016 | $dom->find('li:nth-child(-1n+3)')->each(sub { push @li, shift->text }); |
1017 | is_deeply \@li, [qw(A B C)], 'found first three li elements'; |
1018 | @li = (); |
1019 | $dom->find('li:nth-last-child(-1n+3)')->each(sub { push @li, shift->text }); |
1020 | is_deeply \@li, [qw(F G H)], 'found first three li elements'; |
1021 | @li = (); |
1022 | $dom->find('li:nth-child(3n)')->each(sub { push @li, shift->text }); |
1023 | is_deeply \@li, [qw(C F)], 'found every third li elements'; |
1024 | @li = (); |
1025 | $dom->find('li:nth-last-child(3n)')->each(sub { push @li, shift->text }); |
1026 | is_deeply \@li, [qw(C F)], 'found every third li elements'; |
1027 | @li = (); |
1028 | $dom->find('li:NTH-LAST-CHILD(3N)')->each(sub { push @li, shift->text }); |
1029 | is_deeply \@li, [qw(C F)], 'found every third li elements'; |
1030 | @li = (); |
1031 | $dom->find('li:Nth-Last-Child(3N)')->each(sub { push @li, shift->text }); |
1032 | is_deeply \@li, [qw(C F)], 'found every third li elements'; |
1033 | @li = (); |
eb9737f2 |
1034 | $dom->find('li:nth-child( 3 )')->each(sub { push @li, shift->text }); |
d6512b50 |
1035 | is_deeply \@li, ['C'], 'found third li element'; |
1036 | @li = (); |
eb9737f2 |
1037 | $dom->find('li:nth-last-child( +3 )')->each(sub { push @li, shift->text }); |
d6512b50 |
1038 | is_deeply \@li, ['F'], 'found third last li element'; |
1039 | @li = (); |
1040 | $dom->find('li:nth-child(1n+0)')->each(sub { push @li, shift->text }); |
eb9737f2 |
1041 | is_deeply \@li, [qw(A B C D E F G)], 'found all li elements'; |
1042 | @li = (); |
1043 | $dom->find('li:nth-child(1n-0)')->each(sub { push @li, shift->text }); |
1044 | is_deeply \@li, [qw(A B C D E F G)], 'found all li elements'; |
d6512b50 |
1045 | @li = (); |
1046 | $dom->find('li:nth-child(n+0)')->each(sub { push @li, shift->text }); |
eb9737f2 |
1047 | is_deeply \@li, [qw(A B C D E F G)], 'found all li elements'; |
1048 | @li = (); |
1049 | $dom->find('li:nth-child(n)')->each(sub { push @li, shift->text }); |
1050 | is_deeply \@li, [qw(A B C D E F G)], 'found all li elements'; |
1051 | @li = (); |
1052 | $dom->find('li:nth-child(n+0)')->each(sub { push @li, shift->text }); |
1053 | is_deeply \@li, [qw(A B C D E F G)], 'found all li elements'; |
d6512b50 |
1054 | @li = (); |
1055 | $dom->find('li:NTH-CHILD(N+0)')->each(sub { push @li, shift->text }); |
eb9737f2 |
1056 | is_deeply \@li, [qw(A B C D E F G)], 'found all li elements'; |
d6512b50 |
1057 | @li = (); |
1058 | $dom->find('li:Nth-Child(N+0)')->each(sub { push @li, shift->text }); |
eb9737f2 |
1059 | is_deeply \@li, [qw(A B C D E F G)], 'found all li elements'; |
d6512b50 |
1060 | @li = (); |
1061 | $dom->find('li:nth-child(n)')->each(sub { push @li, shift->text }); |
eb9737f2 |
1062 | is_deeply \@li, [qw(A B C D E F G)], 'found all li elements'; |
1063 | @li = (); |
1064 | $dom->find('li:nth-child(0n+1)')->each(sub { push @li, shift->text }); |
1065 | is_deeply \@li, [qw(A)], 'found first li element'; |
1066 | is $dom->find('li:nth-child(0n+0)')->size, 0, 'no results'; |
1067 | is $dom->find('li:nth-child(0)')->size, 0, 'no results'; |
1068 | is $dom->find('li:nth-child()')->size, 0, 'no results'; |
1069 | is $dom->find('li:nth-child(whatever)')->size, 0, 'no results'; |
1070 | is $dom->find('li:whatever(whatever)')->size, 0, 'no results'; |
d6512b50 |
1071 | |
1072 | # Even more pseudo-classes |
1073 | $dom = DOM::Tiny->new(<<EOF); |
1074 | <ul> |
1075 | <li>A</li> |
1076 | <p>B</p> |
1077 | <li class="test ♥">C</li> |
1078 | <p>D</p> |
1079 | <li>E</li> |
1080 | <li>F</li> |
1081 | <p>G</p> |
1082 | <li>H</li> |
1083 | <li>I</li> |
1084 | </ul> |
1085 | <div> |
1086 | <div class="☃">J</div> |
1087 | </div> |
1088 | <div> |
1089 | <a href="http://www.w3.org/DOM/">DOM</a> |
1090 | <div class="☃">K</div> |
1091 | <a href="http://www.w3.org/DOM/">DOM</a> |
1092 | </div> |
1093 | EOF |
1094 | my @e; |
1095 | $dom->find('ul :nth-child(odd)')->each(sub { push @e, shift->text }); |
1096 | is_deeply \@e, [qw(A C E G I)], 'found all odd elements'; |
1097 | @e = (); |
1098 | $dom->find('li:nth-of-type(odd)')->each(sub { push @e, shift->text }); |
1099 | is_deeply \@e, [qw(A E H)], 'found all odd li elements'; |
1100 | @e = (); |
1101 | $dom->find('li:nth-last-of-type( odd )')->each(sub { push @e, shift->text }); |
1102 | is_deeply \@e, [qw(C F I)], 'found all odd li elements'; |
1103 | @e = (); |
1104 | $dom->find('p:nth-of-type(odd)')->each(sub { push @e, shift->text }); |
1105 | is_deeply \@e, [qw(B G)], 'found all odd p elements'; |
1106 | @e = (); |
1107 | $dom->find('p:nth-last-of-type(odd)')->each(sub { push @e, shift->text }); |
1108 | is_deeply \@e, [qw(B G)], 'found all odd li elements'; |
1109 | @e = (); |
1110 | $dom->find('ul :nth-child(1)')->each(sub { push @e, shift->text }); |
1111 | is_deeply \@e, ['A'], 'found first child'; |
1112 | @e = (); |
1113 | $dom->find('ul :first-child')->each(sub { push @e, shift->text }); |
1114 | is_deeply \@e, ['A'], 'found first child'; |
1115 | @e = (); |
1116 | $dom->find('p:nth-of-type(1)')->each(sub { push @e, shift->text }); |
1117 | is_deeply \@e, ['B'], 'found first child'; |
1118 | @e = (); |
1119 | $dom->find('p:first-of-type')->each(sub { push @e, shift->text }); |
1120 | is_deeply \@e, ['B'], 'found first child'; |
1121 | @e = (); |
1122 | $dom->find('li:nth-of-type(1)')->each(sub { push @e, shift->text }); |
1123 | is_deeply \@e, ['A'], 'found first child'; |
1124 | @e = (); |
1125 | $dom->find('li:first-of-type')->each(sub { push @e, shift->text }); |
1126 | is_deeply \@e, ['A'], 'found first child'; |
1127 | @e = (); |
1128 | $dom->find('ul :nth-last-child(-n+1)')->each(sub { push @e, shift->text }); |
1129 | is_deeply \@e, ['I'], 'found last child'; |
1130 | @e = (); |
1131 | $dom->find('ul :last-child')->each(sub { push @e, shift->text }); |
1132 | is_deeply \@e, ['I'], 'found last child'; |
1133 | @e = (); |
1134 | $dom->find('p:nth-last-of-type(-n+1)')->each(sub { push @e, shift->text }); |
1135 | is_deeply \@e, ['G'], 'found last child'; |
1136 | @e = (); |
1137 | $dom->find('p:last-of-type')->each(sub { push @e, shift->text }); |
1138 | is_deeply \@e, ['G'], 'found last child'; |
1139 | @e = (); |
1140 | $dom->find('li:nth-last-of-type(-n+1)')->each(sub { push @e, shift->text }); |
1141 | is_deeply \@e, ['I'], 'found last child'; |
1142 | @e = (); |
1143 | $dom->find('li:last-of-type')->each(sub { push @e, shift->text }); |
1144 | is_deeply \@e, ['I'], 'found last child'; |
1145 | @e = (); |
1146 | $dom->find('ul :nth-child(-n+3):not(li)')->each(sub { push @e, shift->text }); |
1147 | is_deeply \@e, ['B'], 'found first p element'; |
1148 | @e = (); |
eb9737f2 |
1149 | $dom->find('ul :nth-child(-n+3):NOT(li)')->each(sub { push @e, shift->text }); |
1150 | is_deeply \@e, ['B'], 'found first p element'; |
1151 | @e = (); |
d6512b50 |
1152 | $dom->find('ul :nth-child(-n+3):not(:first-child)') |
1153 | ->each(sub { push @e, shift->text }); |
1154 | is_deeply \@e, [qw(B C)], 'found second and third element'; |
1155 | @e = (); |
1156 | $dom->find('ul :nth-child(-n+3):not(.♥)')->each(sub { push @e, shift->text }); |
1157 | is_deeply \@e, [qw(A B)], 'found first and second element'; |
1158 | @e = (); |
1159 | $dom->find('ul :nth-child(-n+3):not([class$="♥"])') |
1160 | ->each(sub { push @e, shift->text }); |
1161 | is_deeply \@e, [qw(A B)], 'found first and second element'; |
1162 | @e = (); |
1163 | $dom->find('ul :nth-child(-n+3):not(li[class$="♥"])') |
1164 | ->each(sub { push @e, shift->text }); |
1165 | is_deeply \@e, [qw(A B)], 'found first and second element'; |
1166 | @e = (); |
1167 | $dom->find('ul :nth-child(-n+3):not([class$="♥"][class^="test"])') |
1168 | ->each(sub { push @e, shift->text }); |
1169 | is_deeply \@e, [qw(A B)], 'found first and second element'; |
1170 | @e = (); |
1171 | $dom->find('ul :nth-child(-n+3):not(*[class$="♥"])') |
1172 | ->each(sub { push @e, shift->text }); |
1173 | is_deeply \@e, [qw(A B)], 'found first and second element'; |
1174 | @e = (); |
1175 | $dom->find('ul :nth-child(-n+3):not(:nth-child(-n+2))') |
1176 | ->each(sub { push @e, shift->text }); |
1177 | is_deeply \@e, ['C'], 'found third element'; |
1178 | @e = (); |
1179 | $dom->find('ul :nth-child(-n+3):not(:nth-child(1)):not(:nth-child(2))') |
1180 | ->each(sub { push @e, shift->text }); |
1181 | is_deeply \@e, ['C'], 'found third element'; |
1182 | @e = (); |
1183 | $dom->find(':only-child')->each(sub { push @e, shift->text }); |
1184 | is_deeply \@e, ['J'], 'found only child'; |
1185 | @e = (); |
1186 | $dom->find('div :only-of-type')->each(sub { push @e, shift->text }); |
1187 | is_deeply \@e, [qw(J K)], 'found only child'; |
1188 | @e = (); |
1189 | $dom->find('div:only-child')->each(sub { push @e, shift->text }); |
1190 | is_deeply \@e, ['J'], 'found only child'; |
1191 | @e = (); |
1192 | $dom->find('div div:only-of-type')->each(sub { push @e, shift->text }); |
1193 | is_deeply \@e, [qw(J K)], 'found only child'; |
1194 | |
1195 | # Sibling combinator |
1196 | $dom = DOM::Tiny->new(<<EOF); |
1197 | <ul> |
1198 | <li>A</li> |
1199 | <p>B</p> |
1200 | <li>C</li> |
1201 | </ul> |
1202 | <h1>D</h1> |
1203 | <p id="♥">E</p> |
1204 | <p id="☃">F<b>H</b></p> |
1205 | <div>G</div> |
1206 | EOF |
1207 | is $dom->at('li ~ p')->text, 'B', 'right text'; |
1208 | is $dom->at('li + p')->text, 'B', 'right text'; |
1209 | is $dom->at('h1 ~ p ~ p')->text, 'F', 'right text'; |
1210 | is $dom->at('h1 + p ~ p')->text, 'F', 'right text'; |
1211 | is $dom->at('h1 ~ p + p')->text, 'F', 'right text'; |
1212 | is $dom->at('h1 + p + p')->text, 'F', 'right text'; |
1213 | is $dom->at('h1 + p+p')->text, 'F', 'right text'; |
1214 | is $dom->at('ul > li ~ li')->text, 'C', 'right text'; |
1215 | is $dom->at('ul li ~ li')->text, 'C', 'right text'; |
1216 | is $dom->at('ul>li~li')->text, 'C', 'right text'; |
1217 | is $dom->at('ul li li'), undef, 'no result'; |
1218 | is $dom->at('ul ~ li ~ li'), undef, 'no result'; |
1219 | is $dom->at('ul + li ~ li'), undef, 'no result'; |
1220 | is $dom->at('ul > li + li'), undef, 'no result'; |
1221 | is $dom->at('h1 ~ div')->text, 'G', 'right text'; |
1222 | is $dom->at('h1 + div'), undef, 'no result'; |
1223 | is $dom->at('p + div')->text, 'G', 'right text'; |
1224 | is $dom->at('ul + h1 + p + p + div')->text, 'G', 'right text'; |
1225 | is $dom->at('ul + h1 ~ p + div')->text, 'G', 'right text'; |
1226 | is $dom->at('h1 ~ #♥')->text, 'E', 'right text'; |
1227 | is $dom->at('h1 + #♥')->text, 'E', 'right text'; |
1228 | is $dom->at('#♥~#☃')->text, 'F', 'right text'; |
1229 | is $dom->at('#♥+#☃')->text, 'F', 'right text'; |
1230 | is $dom->at('#♥+#☃>b')->text, 'H', 'right text'; |
1231 | is $dom->at('#♥ > #☃'), undef, 'no result'; |
1232 | is $dom->at('#♥ #☃'), undef, 'no result'; |
1233 | is $dom->at('#♥ + #☃ + :nth-last-child(1)')->text, 'G', 'right text'; |
1234 | is $dom->at('#♥ ~ #☃ + :nth-last-child(1)')->text, 'G', 'right text'; |
1235 | is $dom->at('#♥ + #☃ ~ :nth-last-child(1)')->text, 'G', 'right text'; |
1236 | is $dom->at('#♥ ~ #☃ ~ :nth-last-child(1)')->text, 'G', 'right text'; |
1237 | is $dom->at('#♥ + :nth-last-child(2)')->text, 'F', 'right text'; |
1238 | is $dom->at('#♥ ~ :nth-last-child(2)')->text, 'F', 'right text'; |
1239 | is $dom->at('#♥ + #☃ + *:nth-last-child(1)')->text, 'G', 'right text'; |
1240 | is $dom->at('#♥ ~ #☃ + *:nth-last-child(1)')->text, 'G', 'right text'; |
1241 | is $dom->at('#♥ + #☃ ~ *:nth-last-child(1)')->text, 'G', 'right text'; |
1242 | is $dom->at('#♥ ~ #☃ ~ *:nth-last-child(1)')->text, 'G', 'right text'; |
1243 | is $dom->at('#♥ + *:nth-last-child(2)')->text, 'F', 'right text'; |
1244 | is $dom->at('#♥ ~ *:nth-last-child(2)')->text, 'F', 'right text'; |
1245 | |
1246 | # Adding nodes |
1247 | $dom = DOM::Tiny->new(<<EOF); |
1248 | <ul> |
1249 | <li>A</li> |
1250 | <p>B</p> |
1251 | <li>C</li> |
1252 | </ul> |
1253 | <div>D</div> |
1254 | EOF |
1255 | $dom->at('li')->append('<p>A1</p>23'); |
1256 | is "$dom", <<EOF, 'right result'; |
1257 | <ul> |
1258 | <li>A</li><p>A1</p>23 |
1259 | <p>B</p> |
1260 | <li>C</li> |
1261 | </ul> |
1262 | <div>D</div> |
1263 | EOF |
1264 | $dom->at('li')->prepend('24')->prepend('<div>A-1</div>25'); |
1265 | is "$dom", <<EOF, 'right result'; |
1266 | <ul> |
1267 | 24<div>A-1</div>25<li>A</li><p>A1</p>23 |
1268 | <p>B</p> |
1269 | <li>C</li> |
1270 | </ul> |
1271 | <div>D</div> |
1272 | EOF |
1273 | is $dom->at('div')->text, 'A-1', 'right text'; |
1274 | is $dom->at('iv'), undef, 'no result'; |
c7cad649 |
1275 | is $dom->prepend('l')->prepend('alal')->prepend('a')->type, 'root', |
1276 | 'right type'; |
1277 | is "$dom", <<EOF, 'no changes'; |
d6512b50 |
1278 | <ul> |
1279 | 24<div>A-1</div>25<li>A</li><p>A1</p>23 |
1280 | <p>B</p> |
1281 | <li>C</li> |
1282 | </ul> |
1283 | <div>D</div> |
1284 | EOF |
c7cad649 |
1285 | is $dom->append('lalala')->type, 'root', 'right type'; |
1286 | is "$dom", <<EOF, 'no changes'; |
d6512b50 |
1287 | <ul> |
1288 | 24<div>A-1</div>25<li>A</li><p>A1</p>23 |
1289 | <p>B</p> |
1290 | <li>C</li> |
1291 | </ul> |
1292 | <div>D</div> |
1293 | EOF |
1294 | $dom->find('div')->each(sub { shift->append('works') }); |
1295 | is "$dom", <<EOF, 'right result'; |
1296 | <ul> |
1297 | 24<div>A-1</div>works25<li>A</li><p>A1</p>23 |
1298 | <p>B</p> |
1299 | <li>C</li> |
1300 | </ul> |
1301 | <div>D</div>works |
1302 | EOF |
1303 | $dom->at('li')->prepend_content('A3<p>A2</p>')->prepend_content('A4'); |
1304 | is $dom->at('li')->text, 'A4A3 A', 'right text'; |
1305 | is "$dom", <<EOF, 'right result'; |
1306 | <ul> |
1307 | 24<div>A-1</div>works25<li>A4A3<p>A2</p>A</li><p>A1</p>23 |
1308 | <p>B</p> |
1309 | <li>C</li> |
1310 | </ul> |
1311 | <div>D</div>works |
1312 | EOF |
1313 | $dom->find('li')->[1]->append_content('<p>C2</p>C3')->append_content(' C4') |
1314 | ->append_content('C5'); |
1315 | is $dom->find('li')->[1]->text, 'C C3 C4C5', 'right text'; |
1316 | is "$dom", <<EOF, 'right result'; |
1317 | <ul> |
1318 | 24<div>A-1</div>works25<li>A4A3<p>A2</p>A</li><p>A1</p>23 |
1319 | <p>B</p> |
1320 | <li>C<p>C2</p>C3 C4C5</li> |
1321 | </ul> |
1322 | <div>D</div>works |
1323 | EOF |
1324 | |
1325 | # Optional "head" and "body" tags |
1326 | $dom = DOM::Tiny->new(<<EOF); |
1327 | <html> |
1328 | <head> |
1329 | <title>foo</title> |
1330 | <body>bar |
1331 | EOF |
1332 | is $dom->at('html > head > title')->text, 'foo', 'right text'; |
1333 | is $dom->at('html > body')->text, 'bar', 'right text'; |
1334 | |
1335 | # Optional "li" tag |
1336 | $dom = DOM::Tiny->new(<<EOF); |
1337 | <ul> |
1338 | <li> |
1339 | <ol> |
1340 | <li>F |
1341 | <li>G |
1342 | </ol> |
1343 | <li>A</li> |
1344 | <LI>B |
1345 | <li>C</li> |
1346 | <li>D |
1347 | <li>E |
1348 | </ul> |
1349 | EOF |
1350 | is $dom->find('ul > li > ol > li')->[0]->text, 'F', 'right text'; |
1351 | is $dom->find('ul > li > ol > li')->[1]->text, 'G', 'right text'; |
1352 | is $dom->find('ul > li')->[1]->text, 'A', 'right text'; |
1353 | is $dom->find('ul > li')->[2]->text, 'B', 'right text'; |
1354 | is $dom->find('ul > li')->[3]->text, 'C', 'right text'; |
1355 | is $dom->find('ul > li')->[4]->text, 'D', 'right text'; |
1356 | is $dom->find('ul > li')->[5]->text, 'E', 'right text'; |
1357 | |
1358 | # Optional "p" tag |
1359 | $dom = DOM::Tiny->new(<<EOF); |
1360 | <div> |
1361 | <p>A</p> |
1362 | <P>B |
1363 | <p>C</p> |
1364 | <p>D<div>X</div> |
1365 | <p>E<img src="foo.png"> |
1366 | <p>F<br>G |
1367 | <p>H |
1368 | </div> |
1369 | EOF |
1370 | is $dom->find('div > p')->[0]->text, 'A', 'right text'; |
1371 | is $dom->find('div > p')->[1]->text, 'B', 'right text'; |
1372 | is $dom->find('div > p')->[2]->text, 'C', 'right text'; |
1373 | is $dom->find('div > p')->[3]->text, 'D', 'right text'; |
1374 | is $dom->find('div > p')->[4]->text, 'E', 'right text'; |
1375 | is $dom->find('div > p')->[5]->text, 'F G', 'right text'; |
1376 | is $dom->find('div > p')->[6]->text, 'H', 'right text'; |
1377 | is $dom->find('div > p > p')->[0], undef, 'no results'; |
1378 | is $dom->at('div > p > img')->attr->{src}, 'foo.png', 'right attribute'; |
1379 | is $dom->at('div > div')->text, 'X', 'right text'; |
1380 | |
1381 | # Optional "dt" and "dd" tags |
1382 | $dom = DOM::Tiny->new(<<EOF); |
1383 | <dl> |
1384 | <dt>A</dt> |
1385 | <DD>B |
1386 | <dt>C</dt> |
1387 | <dd>D |
1388 | <dt>E |
1389 | <dd>F |
1390 | </dl> |
1391 | EOF |
1392 | is $dom->find('dl > dt')->[0]->text, 'A', 'right text'; |
1393 | is $dom->find('dl > dd')->[0]->text, 'B', 'right text'; |
1394 | is $dom->find('dl > dt')->[1]->text, 'C', 'right text'; |
1395 | is $dom->find('dl > dd')->[1]->text, 'D', 'right text'; |
1396 | is $dom->find('dl > dt')->[2]->text, 'E', 'right text'; |
1397 | is $dom->find('dl > dd')->[2]->text, 'F', 'right text'; |
1398 | |
1399 | # Optional "rp" and "rt" tags |
1400 | $dom = DOM::Tiny->new(<<EOF); |
1401 | <ruby> |
1402 | <rp>A</rp> |
1403 | <RT>B |
1404 | <rp>C</rp> |
1405 | <rt>D |
1406 | <rp>E |
1407 | <rt>F |
1408 | </ruby> |
1409 | EOF |
1410 | is $dom->find('ruby > rp')->[0]->text, 'A', 'right text'; |
1411 | is $dom->find('ruby > rt')->[0]->text, 'B', 'right text'; |
1412 | is $dom->find('ruby > rp')->[1]->text, 'C', 'right text'; |
1413 | is $dom->find('ruby > rt')->[1]->text, 'D', 'right text'; |
1414 | is $dom->find('ruby > rp')->[2]->text, 'E', 'right text'; |
1415 | is $dom->find('ruby > rt')->[2]->text, 'F', 'right text'; |
1416 | |
1417 | # Optional "optgroup" and "option" tags |
1418 | $dom = DOM::Tiny->new(<<EOF); |
1419 | <div> |
1420 | <optgroup>A |
1421 | <option id="foo">B |
1422 | <option>C</option> |
1423 | <option>D |
1424 | <OPTGROUP>E |
1425 | <option>F |
1426 | <optgroup>G |
1427 | <option>H |
1428 | </div> |
1429 | EOF |
1430 | is $dom->find('div > optgroup')->[0]->text, 'A', 'right text'; |
1431 | is $dom->find('div > optgroup > #foo')->[0]->text, 'B', 'right text'; |
1432 | is $dom->find('div > optgroup > option')->[1]->text, 'C', 'right text'; |
1433 | is $dom->find('div > optgroup > option')->[2]->text, 'D', 'right text'; |
1434 | is $dom->find('div > optgroup')->[1]->text, 'E', 'right text'; |
1435 | is $dom->find('div > optgroup > option')->[3]->text, 'F', 'right text'; |
1436 | is $dom->find('div > optgroup')->[2]->text, 'G', 'right text'; |
1437 | is $dom->find('div > optgroup > option')->[4]->text, 'H', 'right text'; |
1438 | |
1439 | # Optional "colgroup" tag |
1440 | $dom = DOM::Tiny->new(<<EOF); |
1441 | <table> |
1442 | <col id=morefail> |
1443 | <col id=fail> |
1444 | <colgroup> |
1445 | <col id=foo> |
1446 | <col class=foo> |
1447 | <colgroup> |
1448 | <col id=bar> |
1449 | </table> |
1450 | EOF |
1451 | is $dom->find('table > col')->[0]->attr->{id}, 'morefail', 'right attribute'; |
1452 | is $dom->find('table > col')->[1]->attr->{id}, 'fail', 'right attribute'; |
1453 | is $dom->find('table > colgroup > col')->[0]->attr->{id}, 'foo', |
1454 | 'right attribute'; |
1455 | is $dom->find('table > colgroup > col')->[1]->attr->{class}, 'foo', |
1456 | 'right attribute'; |
1457 | is $dom->find('table > colgroup > col')->[2]->attr->{id}, 'bar', |
1458 | 'right attribute'; |
1459 | |
1460 | # Optional "thead", "tbody", "tfoot", "tr", "th" and "td" tags |
1461 | $dom = DOM::Tiny->new(<<EOF); |
1462 | <table> |
1463 | <thead> |
1464 | <tr> |
1465 | <th>A</th> |
1466 | <th>D |
1467 | <tfoot> |
1468 | <tr> |
1469 | <td>C |
1470 | <tbody> |
1471 | <tr> |
1472 | <td>B |
1473 | </table> |
1474 | EOF |
1475 | is $dom->at('table > thead > tr > th')->text, 'A', 'right text'; |
1476 | is $dom->find('table > thead > tr > th')->[1]->text, 'D', 'right text'; |
1477 | is $dom->at('table > tbody > tr > td')->text, 'B', 'right text'; |
1478 | is $dom->at('table > tfoot > tr > td')->text, 'C', 'right text'; |
1479 | |
1480 | # Optional "colgroup", "thead", "tbody", "tr", "th" and "td" tags |
1481 | $dom = DOM::Tiny->new(<<EOF); |
1482 | <table> |
1483 | <col id=morefail> |
1484 | <col id=fail> |
1485 | <colgroup> |
1486 | <col id=foo /> |
1487 | <col class=foo> |
1488 | <colgroup> |
1489 | <col id=bar> |
1490 | </colgroup> |
1491 | <thead> |
1492 | <tr> |
1493 | <th>A</th> |
1494 | <th>D |
1495 | <tbody> |
1496 | <tr> |
1497 | <td>B |
1498 | <tbody> |
1499 | <tr> |
1500 | <td>E |
1501 | </table> |
1502 | EOF |
1503 | is $dom->find('table > col')->[0]->attr->{id}, 'morefail', 'right attribute'; |
1504 | is $dom->find('table > col')->[1]->attr->{id}, 'fail', 'right attribute'; |
1505 | is $dom->find('table > colgroup > col')->[0]->attr->{id}, 'foo', |
1506 | 'right attribute'; |
1507 | is $dom->find('table > colgroup > col')->[1]->attr->{class}, 'foo', |
1508 | 'right attribute'; |
1509 | is $dom->find('table > colgroup > col')->[2]->attr->{id}, 'bar', |
1510 | 'right attribute'; |
1511 | is $dom->at('table > thead > tr > th')->text, 'A', 'right text'; |
1512 | is $dom->find('table > thead > tr > th')->[1]->text, 'D', 'right text'; |
1513 | is $dom->at('table > tbody > tr > td')->text, 'B', 'right text'; |
1514 | is $dom->find('table > tbody > tr > td')->map('text')->join("\n"), "B\nE", |
1515 | 'right text'; |
1516 | |
1517 | # Optional "colgroup", "tbody", "tr", "th" and "td" tags |
1518 | $dom = DOM::Tiny->new(<<EOF); |
1519 | <table> |
1520 | <colgroup> |
1521 | <col id=foo /> |
1522 | <col class=foo> |
1523 | <colgroup> |
1524 | <col id=bar> |
1525 | </colgroup> |
1526 | <tbody> |
1527 | <tr> |
1528 | <td>B |
1529 | </table> |
1530 | EOF |
1531 | is $dom->find('table > colgroup > col')->[0]->attr->{id}, 'foo', |
1532 | 'right attribute'; |
1533 | is $dom->find('table > colgroup > col')->[1]->attr->{class}, 'foo', |
1534 | 'right attribute'; |
1535 | is $dom->find('table > colgroup > col')->[2]->attr->{id}, 'bar', |
1536 | 'right attribute'; |
1537 | is $dom->at('table > tbody > tr > td')->text, 'B', 'right text'; |
1538 | |
1539 | # Optional "tr" and "td" tags |
1540 | $dom = DOM::Tiny->new(<<EOF); |
1541 | <table> |
1542 | <tr> |
1543 | <td>A |
1544 | <td>B</td> |
1545 | <tr> |
1546 | <td>C |
1547 | </tr> |
1548 | <tr> |
1549 | <td>D |
1550 | </table> |
1551 | EOF |
1552 | is $dom->find('table > tr > td')->[0]->text, 'A', 'right text'; |
1553 | is $dom->find('table > tr > td')->[1]->text, 'B', 'right text'; |
1554 | is $dom->find('table > tr > td')->[2]->text, 'C', 'right text'; |
1555 | is $dom->find('table > tr > td')->[3]->text, 'D', 'right text'; |
1556 | |
1557 | # Real world table |
1558 | $dom = DOM::Tiny->new(<<EOF); |
1559 | <html> |
1560 | <head> |
1561 | <title>Real World!</title> |
1562 | <body> |
1563 | <p>Just a test |
1564 | <table class=RealWorld> |
1565 | <thead> |
1566 | <tr> |
1567 | <th class=one>One |
1568 | <th class=two>Two |
1569 | <th class=three>Three |
1570 | <th class=four>Four |
1571 | <tbody> |
1572 | <tr> |
1573 | <td class=alpha>Alpha |
1574 | <td class=beta>Beta |
1575 | <td class=gamma><a href="#gamma">Gamma</a> |
1576 | <td class=delta>Delta |
1577 | <tr> |
1578 | <td class=alpha>Alpha Two |
1579 | <td class=beta>Beta Two |
1580 | <td class=gamma><a href="#gamma-two">Gamma Two</a> |
1581 | <td class=delta>Delta Two |
1582 | </table> |
1583 | EOF |
1584 | is $dom->find('html > head > title')->[0]->text, 'Real World!', 'right text'; |
1585 | is $dom->find('html > body > p')->[0]->text, 'Just a test', 'right text'; |
1586 | is $dom->find('p')->[0]->text, 'Just a test', 'right text'; |
1587 | is $dom->find('thead > tr > .three')->[0]->text, 'Three', 'right text'; |
1588 | is $dom->find('thead > tr > .four')->[0]->text, 'Four', 'right text'; |
1589 | is $dom->find('tbody > tr > .beta')->[0]->text, 'Beta', 'right text'; |
1590 | is $dom->find('tbody > tr > .gamma')->[0]->text, '', 'no text'; |
1591 | is $dom->find('tbody > tr > .gamma > a')->[0]->text, 'Gamma', 'right text'; |
1592 | is $dom->find('tbody > tr > .alpha')->[1]->text, 'Alpha Two', 'right text'; |
1593 | is $dom->find('tbody > tr > .gamma > a')->[1]->text, 'Gamma Two', 'right text'; |
1594 | my @following |
1595 | = $dom->find('tr > td:nth-child(1)')->map(following => ':nth-child(even)') |
1596 | ->flatten->map('all_text')->each; |
1597 | is_deeply \@following, ['Beta', 'Delta', 'Beta Two', 'Delta Two'], |
1598 | 'right results'; |
1599 | |
1600 | # Real world list |
1601 | $dom = DOM::Tiny->new(<<EOF); |
1602 | <html> |
1603 | <head> |
1604 | <title>Real World!</title> |
1605 | <body> |
1606 | <ul> |
1607 | <li> |
1608 | Test |
1609 | <br> |
1610 | 123 |
1611 | <p> |
1612 | |
1613 | <li> |
1614 | Test |
1615 | <br> |
1616 | 321 |
1617 | <p> |
1618 | <li> |
1619 | Test |
1620 | 3 |
1621 | 2 |
1622 | 1 |
1623 | <p> |
1624 | </ul> |
1625 | EOF |
1626 | is $dom->find('html > head > title')->[0]->text, 'Real World!', 'right text'; |
1627 | is $dom->find('body > ul > li')->[0]->text, 'Test 123', 'right text'; |
1628 | is $dom->find('body > ul > li > p')->[0]->text, '', 'no text'; |
1629 | is $dom->find('body > ul > li')->[1]->text, 'Test 321', 'right text'; |
1630 | is $dom->find('body > ul > li > p')->[1]->text, '', 'no text'; |
1631 | is $dom->find('body > ul > li')->[1]->all_text, 'Test 321', 'right text'; |
1632 | is $dom->find('body > ul > li > p')->[1]->all_text, '', 'no text'; |
1633 | is $dom->find('body > ul > li')->[2]->text, 'Test 3 2 1', 'right text'; |
1634 | is $dom->find('body > ul > li > p')->[2]->text, '', 'no text'; |
1635 | is $dom->find('body > ul > li')->[2]->all_text, 'Test 3 2 1', 'right text'; |
1636 | is $dom->find('body > ul > li > p')->[2]->all_text, '', 'no text'; |
1637 | |
1638 | # Advanced whitespace trimming (punctuation) |
1639 | $dom = DOM::Tiny->new(<<EOF); |
1640 | <html> |
1641 | <head> |
1642 | <title>Real World!</title> |
1643 | <body> |
1644 | <div>foo <strong>bar</strong>.</div> |
1645 | <div>foo<strong>, bar</strong>baz<strong>; yada</strong>.</div> |
1646 | <div>foo<strong>: bar</strong>baz<strong>? yada</strong>!</div> |
1647 | EOF |
1648 | is $dom->find('html > head > title')->[0]->text, 'Real World!', 'right text'; |
1649 | is $dom->find('body > div')->[0]->all_text, 'foo bar.', 'right text'; |
1650 | is $dom->find('body > div')->[1]->all_text, 'foo, bar baz; yada.', 'right text'; |
1651 | is $dom->find('body > div')->[1]->text, 'foo baz.', 'right text'; |
1652 | is $dom->find('body > div')->[2]->all_text, 'foo: bar baz? yada!', 'right text'; |
1653 | is $dom->find('body > div')->[2]->text, 'foo baz!', 'right text'; |
1654 | |
1655 | # Real world JavaScript and CSS |
1656 | $dom = DOM::Tiny->new(<<EOF); |
1657 | <html> |
1658 | <head> |
1659 | <style test=works>#style { foo: style('<test>'); }</style> |
1660 | <script> |
1661 | if (a < b) { |
1662 | alert('<123>'); |
1663 | } |
1664 | </script> |
1665 | < sCriPt two="23" >if (b > c) { alert('&<ohoh>') }< / scRiPt > |
1666 | <body>Foo!</body> |
1667 | EOF |
1668 | is $dom->find('html > body')->[0]->text, 'Foo!', 'right text'; |
1669 | is $dom->find('html > head > style')->[0]->text, |
1670 | "#style { foo: style('<test>'); }", 'right text'; |
1671 | is $dom->find('html > head > script')->[0]->text, |
1672 | "\n if (a < b) {\n alert('<123>');\n }\n ", 'right text'; |
1673 | is $dom->find('html > head > script')->[1]->text, |
1674 | "if (b > c) { alert('&<ohoh>') }", 'right text'; |
1675 | |
1676 | # More real world JavaScript |
1677 | $dom = DOM::Tiny->new(<<EOF); |
1678 | <!DOCTYPE html> |
1679 | <html> |
1680 | <head> |
1681 | <title>Foo</title> |
1682 | <script src="/js/one.js"></script> |
1683 | <script src="/js/two.js"></script> |
1684 | <script src="/js/three.js"></script> |
1685 | </head> |
1686 | <body>Bar</body> |
1687 | </html> |
1688 | EOF |
1689 | is $dom->at('title')->text, 'Foo', 'right text'; |
1690 | is $dom->find('html > head > script')->[0]->attr('src'), '/js/one.js', |
1691 | 'right attribute'; |
1692 | is $dom->find('html > head > script')->[1]->attr('src'), '/js/two.js', |
1693 | 'right attribute'; |
1694 | is $dom->find('html > head > script')->[2]->attr('src'), '/js/three.js', |
1695 | 'right attribute'; |
1696 | is $dom->find('html > head > script')->[2]->text, '', 'no text'; |
1697 | is $dom->at('html > body')->text, 'Bar', 'right text'; |
1698 | |
1699 | # Even more real world JavaScript |
1700 | $dom = DOM::Tiny->new(<<EOF); |
1701 | <!DOCTYPE html> |
1702 | <html> |
1703 | <head> |
1704 | <title>Foo</title> |
1705 | <script src="/js/one.js"></script> |
1706 | <script src="/js/two.js"></script> |
1707 | <script src="/js/three.js"> |
1708 | </head> |
1709 | <body>Bar</body> |
1710 | </html> |
1711 | EOF |
1712 | is $dom->at('title')->text, 'Foo', 'right text'; |
1713 | is $dom->find('html > head > script')->[0]->attr('src'), '/js/one.js', |
1714 | 'right attribute'; |
1715 | is $dom->find('html > head > script')->[1]->attr('src'), '/js/two.js', |
1716 | 'right attribute'; |
1717 | is $dom->find('html > head > script')->[2]->attr('src'), '/js/three.js', |
1718 | 'right attribute'; |
1719 | is $dom->find('html > head > script')->[2]->text, '', 'no text'; |
1720 | is $dom->at('html > body')->text, 'Bar', 'right text'; |
1721 | |
1722 | # Inline DTD |
1723 | $dom = DOM::Tiny->new(<<EOF); |
1724 | <?xml version="1.0"?> |
1725 | <!-- This is a Test! --> |
1726 | <!DOCTYPE root [ |
1727 | <!ELEMENT root (#PCDATA)> |
1728 | <!ATTLIST root att CDATA #REQUIRED> |
1729 | ]> |
1730 | <root att="test"> |
1731 | <![CDATA[<hello>world</hello>]]> |
1732 | </root> |
1733 | EOF |
1734 | ok $dom->xml, 'XML mode detected'; |
1735 | is $dom->at('root')->attr('att'), 'test', 'right attribute'; |
1736 | is $dom->tree->[5][1], ' root [ |
1737 | <!ELEMENT root (#PCDATA)> |
1738 | <!ATTLIST root att CDATA #REQUIRED> |
1739 | ]', 'right doctype'; |
1740 | is $dom->at('root')->text, '<hello>world</hello>', 'right text'; |
1741 | $dom = DOM::Tiny->new(<<EOF); |
1742 | <!doctype book |
1743 | SYSTEM "usr.dtd" |
1744 | [ |
1745 | <!ENTITY test "yeah"> |
1746 | ]> |
1747 | <foo /> |
1748 | EOF |
1749 | is $dom->tree->[1][1], ' book |
1750 | SYSTEM "usr.dtd" |
1751 | [ |
1752 | <!ENTITY test "yeah"> |
1753 | ]', 'right doctype'; |
1754 | ok !$dom->xml, 'XML mode not detected'; |
1755 | is $dom->at('foo'), '<foo></foo>', 'right element'; |
1756 | $dom = DOM::Tiny->new(<<EOF); |
1757 | <?xml version="1.0" encoding = 'utf-8'?> |
1758 | <!DOCTYPE foo [ |
1759 | <!ELEMENT foo ANY> |
1760 | <!ATTLIST foo xml:lang CDATA #IMPLIED> |
1761 | <!ENTITY % e SYSTEM "myentities.ent"> |
1762 | %myentities; |
1763 | ] > |
1764 | <foo xml:lang="de">Check!</fOo> |
1765 | EOF |
1766 | ok $dom->xml, 'XML mode detected'; |
1767 | is $dom->tree->[3][1], ' foo [ |
1768 | <!ELEMENT foo ANY> |
1769 | <!ATTLIST foo xml:lang CDATA #IMPLIED> |
1770 | <!ENTITY % e SYSTEM "myentities.ent"> |
1771 | %myentities; |
1772 | ] ', 'right doctype'; |
1773 | is $dom->at('foo')->attr->{'xml:lang'}, 'de', 'right attribute'; |
1774 | is $dom->at('foo')->text, 'Check!', 'right text'; |
1775 | $dom = DOM::Tiny->new(<<EOF); |
1776 | <!DOCTYPE TESTSUITE PUBLIC "my.dtd" 'mhhh' [ |
1777 | <!ELEMENT foo ANY> |
1778 | <!ATTLIST foo bar ENTITY 'true'> |
1779 | <!ENTITY system_entities SYSTEM 'systems.xml'> |
1780 | <!ENTITY leertaste ' '> |
1781 | <!-- This is a comment --> |
1782 | <!NOTATION hmmm SYSTEM "hmmm"> |
1783 | ] > |
1784 | <?check for-nothing?> |
1785 | <foo bar='false'>&leertaste;!!!</foo> |
1786 | EOF |
1787 | is $dom->tree->[1][1], ' TESTSUITE PUBLIC "my.dtd" \'mhhh\' [ |
1788 | <!ELEMENT foo ANY> |
1789 | <!ATTLIST foo bar ENTITY \'true\'> |
1790 | <!ENTITY system_entities SYSTEM \'systems.xml\'> |
1791 | <!ENTITY leertaste \' \'> |
1792 | <!-- This is a comment --> |
1793 | <!NOTATION hmmm SYSTEM "hmmm"> |
1794 | ] ', 'right doctype'; |
1795 | is $dom->at('foo')->attr('bar'), 'false', 'right attribute'; |
1796 | |
1797 | # Broken "font" block and useless end tags |
1798 | $dom = DOM::Tiny->new(<<EOF); |
1799 | <html> |
1800 | <head><title>Test</title></head> |
1801 | <body> |
1802 | <table> |
1803 | <tr><td><font>test</td></font></tr> |
1804 | </tr> |
1805 | </table> |
1806 | </body> |
1807 | </html> |
1808 | EOF |
1809 | is $dom->at('html > head > title')->text, 'Test', 'right text'; |
1810 | is $dom->at('html body table tr td > font')->text, 'test', 'right text'; |
1811 | |
1812 | # Different broken "font" block |
1813 | $dom = DOM::Tiny->new(<<EOF); |
1814 | <html> |
1815 | <head><title>Test</title></head> |
1816 | <body> |
1817 | <font> |
1818 | <table> |
1819 | <tr> |
1820 | <td>test1<br></td></font> |
1821 | <td>test2<br> |
1822 | </table> |
1823 | </body> |
1824 | </html> |
1825 | EOF |
1826 | is $dom->at('html > head > title')->text, 'Test', 'right text'; |
1827 | is $dom->find('html > body > font > table > tr > td')->[0]->text, 'test1', |
1828 | 'right text'; |
1829 | is $dom->find('html > body > font > table > tr > td')->[1]->text, 'test2', |
1830 | 'right text'; |
1831 | |
1832 | # Broken "font" and "div" blocks |
1833 | $dom = DOM::Tiny->new(<<EOF); |
1834 | <html> |
1835 | <head><title>Test</title></head> |
1836 | <body> |
1837 | <font> |
1838 | <div>test1<br> |
1839 | <div>test2<br></font> |
1840 | </div> |
1841 | </body> |
1842 | </html> |
1843 | EOF |
1844 | is $dom->at('html head title')->text, 'Test', 'right text'; |
1845 | is $dom->at('html body font > div')->text, 'test1', 'right text'; |
1846 | is $dom->at('html body font > div > div')->text, 'test2', 'right text'; |
1847 | |
1848 | # Broken "div" blocks |
1849 | $dom = DOM::Tiny->new(<<EOF); |
1850 | <html> |
1851 | <head><title>Test</title></head> |
1852 | <body> |
1853 | <div> |
1854 | <table> |
1855 | <tr><td><div>test</td></div></tr> |
1856 | </div> |
1857 | </table> |
1858 | </body> |
1859 | </html> |
1860 | EOF |
1861 | is $dom->at('html head title')->text, 'Test', 'right text'; |
1862 | is $dom->at('html body div table tr td > div')->text, 'test', 'right text'; |
1863 | |
1864 | # And another broken "font" block |
1865 | $dom = DOM::Tiny->new(<<EOF); |
1866 | <html> |
1867 | <head><title>Test</title></head> |
1868 | <body> |
1869 | <table> |
1870 | <tr> |
1871 | <td><font><br>te<br>st<br>1</td></font> |
1872 | <td>x1<td><img>tes<br>t2</td> |
1873 | <td>x2<td><font>t<br>est3</font></td> |
1874 | </tr> |
1875 | </table> |
1876 | </body> |
1877 | </html> |
1878 | EOF |
1879 | is $dom->at('html > head > title')->text, 'Test', 'right text'; |
1880 | is $dom->find('html body table tr > td > font')->[0]->text, 'te st 1', |
1881 | 'right text'; |
1882 | is $dom->find('html body table tr > td')->[1]->text, 'x1', 'right text'; |
1883 | is $dom->find('html body table tr > td')->[2]->text, 'tes t2', 'right text'; |
1884 | is $dom->find('html body table tr > td')->[3]->text, 'x2', 'right text'; |
1885 | is $dom->find('html body table tr > td')->[5], undef, 'no result'; |
1886 | is $dom->find('html body table tr > td')->size, 5, 'right number of elements'; |
1887 | is $dom->find('html body table tr > td > font')->[1]->text, 't est3', |
1888 | 'right text'; |
1889 | is $dom->find('html body table tr > td > font')->[2], undef, 'no result'; |
1890 | is $dom->find('html body table tr > td > font')->size, 2, |
1891 | 'right number of elements'; |
1892 | is $dom, <<EOF, 'right result'; |
1893 | <html> |
1894 | <head><title>Test</title></head> |
1895 | <body> |
1896 | <table> |
1897 | <tr> |
1898 | <td><font><br>te<br>st<br>1</font></td> |
1899 | <td>x1</td><td><img>tes<br>t2</td> |
1900 | <td>x2</td><td><font>t<br>est3</font></td> |
1901 | </tr> |
1902 | </table> |
1903 | </body> |
1904 | </html> |
1905 | EOF |
1906 | |
1907 | # A collection of wonderful screwups |
1908 | $dom = DOM::Tiny->new(<<'EOF'); |
1909 | <!DOCTYPE html> |
1910 | <html lang="en"> |
1911 | <head><title>Wonderful Screwups</title></head> |
1912 | <body id="screw-up"> |
1913 | <div> |
1914 | <div class="ewww"> |
1915 | <a href="/test" target='_blank'><img src="/test.png"></a> |
1916 | <a href='/real bad' screwup: http://localhost/bad' target='_blank'> |
1917 | <img src="/test2.png"> |
1918 | </div> |
1919 | </mt:If> |
1920 | </div> |
1921 | <b>>la<>la<<>>la<</b> |
1922 | </body> |
1923 | </html> |
1924 | EOF |
1925 | is $dom->at('#screw-up > b')->text, '>la<>la<<>>la<', 'right text'; |
1926 | is $dom->at('#screw-up .ewww > a > img')->attr('src'), '/test.png', |
1927 | 'right attribute'; |
1928 | is $dom->find('#screw-up .ewww > a > img')->[1]->attr('src'), '/test2.png', |
1929 | 'right attribute'; |
1930 | is $dom->find('#screw-up .ewww > a > img')->[2], undef, 'no result'; |
1931 | is $dom->find('#screw-up .ewww > a > img')->size, 2, 'right number of elements'; |
1932 | |
1933 | # Broken "br" tag |
1934 | $dom = DOM::Tiny->new('<br< abc abc abc abc abc abc abc abc<p>Test</p>'); |
1935 | is $dom->at('p')->text, 'Test', 'right text'; |
1936 | |
1937 | # Modifying an XML document |
1938 | $dom = DOM::Tiny->new(<<'EOF'); |
1939 | <?xml version='1.0' encoding='UTF-8'?> |
1940 | <XMLTest /> |
1941 | EOF |
1942 | ok $dom->xml, 'XML mode detected'; |
1943 | $dom->at('XMLTest')->content('<Element />'); |
1944 | my $element = $dom->at('Element'); |
1945 | is $element->tag, 'Element', 'right tag'; |
1946 | ok $element->xml, 'XML mode active'; |
1947 | $element = $dom->at('XMLTest')->children->[0]; |
1948 | is $element->tag, 'Element', 'right child'; |
1949 | is $element->parent->tag, 'XMLTest', 'right parent'; |
1950 | ok $element->root->xml, 'XML mode active'; |
1951 | $dom->replace('<XMLTest2 /><XMLTest3 just="works" />'); |
1952 | ok $dom->xml, 'XML mode active'; |
1953 | $dom->at('XMLTest2')->{foo} = undef; |
1954 | is $dom, '<XMLTest2 foo="foo" /><XMLTest3 just="works" />', 'right result'; |
1955 | |
1956 | # Ensure HTML semantics |
1957 | ok !DOM::Tiny->new->xml(undef)->parse('<?xml version="1.0"?>')->xml, |
1958 | 'XML mode not detected'; |
1959 | $dom |
1960 | = DOM::Tiny->new->xml(0)->parse('<?xml version="1.0"?><br><div>Test</div>'); |
1961 | is $dom->at('div:root')->text, 'Test', 'right text'; |
1962 | |
1963 | # Ensure XML semantics |
1964 | ok !!DOM::Tiny->new->xml(1)->parse('<foo />')->xml, 'XML mode active'; |
1965 | $dom = DOM::Tiny->new(<<'EOF'); |
1966 | <?xml version='1.0' encoding='UTF-8'?> |
1967 | <script> |
1968 | <table> |
1969 | <td> |
1970 | <tr><thead>foo<thead></tr> |
1971 | </td> |
1972 | <td> |
1973 | <tr><thead>bar<thead></tr> |
1974 | </td> |
1975 | </table> |
1976 | </script> |
1977 | EOF |
1978 | is $dom->find('table > td > tr > thead')->[0]->text, 'foo', 'right text'; |
1979 | is $dom->find('script > table > td > tr > thead')->[1]->text, 'bar', |
1980 | 'right text'; |
1981 | is $dom->find('table > td > tr > thead')->[2], undef, 'no result'; |
1982 | is $dom->find('table > td > tr > thead')->size, 2, 'right number of elements'; |
1983 | |
1984 | # Ensure XML semantics again |
1985 | $dom = DOM::Tiny->new->xml(1)->parse(<<'EOF'); |
1986 | <table> |
1987 | <td> |
1988 | <tr><thead>foo<thead></tr> |
1989 | </td> |
1990 | <td> |
1991 | <tr><thead>bar<thead></tr> |
1992 | </td> |
1993 | </table> |
1994 | EOF |
1995 | is $dom->find('table > td > tr > thead')->[0]->text, 'foo', 'right text'; |
1996 | is $dom->find('table > td > tr > thead')->[1]->text, 'bar', 'right text'; |
1997 | is $dom->find('table > td > tr > thead')->[2], undef, 'no result'; |
1998 | is $dom->find('table > td > tr > thead')->size, 2, 'right number of elements'; |
1999 | |
2000 | # Nested tables |
2001 | $dom = DOM::Tiny->new(<<'EOF'); |
2002 | <table id="foo"> |
2003 | <tr> |
2004 | <td> |
2005 | <table id="bar"> |
2006 | <tr> |
2007 | <td>baz</td> |
2008 | </tr> |
2009 | </table> |
2010 | </td> |
2011 | </tr> |
2012 | </table> |
2013 | EOF |
2014 | is $dom->find('#foo > tr > td > #bar > tr >td')->[0]->text, 'baz', 'right text'; |
2015 | is $dom->find('table > tr > td > table > tr >td')->[0]->text, 'baz', |
2016 | 'right text'; |
2017 | |
2018 | # Nested find |
2019 | $dom->parse(<<EOF); |
2020 | <c> |
2021 | <a>foo</a> |
2022 | <b> |
2023 | <a>bar</a> |
2024 | <c> |
2025 | <a>baz</a> |
2026 | <d> |
2027 | <a>yada</a> |
2028 | </d> |
2029 | </c> |
2030 | </b> |
2031 | </c> |
2032 | EOF |
2033 | my @results; |
2034 | $dom->find('b')->each( |
2035 | sub { |
2036 | $_->find('a')->each(sub { push @results, $_->text }); |
2037 | } |
2038 | ); |
2039 | is_deeply \@results, [qw(bar baz yada)], 'right results'; |
2040 | @results = (); |
2041 | $dom->find('a')->each(sub { push @results, $_->text }); |
2042 | is_deeply \@results, [qw(foo bar baz yada)], 'right results'; |
2043 | @results = (); |
2044 | $dom->find('b')->each( |
2045 | sub { |
2046 | $_->find('c a')->each(sub { push @results, $_->text }); |
2047 | } |
2048 | ); |
2049 | is_deeply \@results, [qw(baz yada)], 'right results'; |
2050 | is $dom->at('b')->at('a')->text, 'bar', 'right text'; |
2051 | is $dom->at('c > b > a')->text, 'bar', 'right text'; |
2052 | is $dom->at('b')->at('c > b > a'), undef, 'no result'; |
2053 | |
2054 | # Direct hash access to attributes in XML mode |
2055 | $dom = DOM::Tiny->new->xml(1)->parse(<<EOF); |
2056 | <a id="one"> |
2057 | <B class="two" test> |
2058 | foo |
2059 | <c id="three">bar</c> |
2060 | <c ID="four">baz</c> |
2061 | </B> |
2062 | </a> |
2063 | EOF |
2064 | ok $dom->xml, 'XML mode active'; |
2065 | is $dom->at('a')->{id}, 'one', 'right attribute'; |
2066 | is_deeply [sort keys %{$dom->at('a')}], ['id'], 'right attributes'; |
2067 | is $dom->at('a')->at('B')->text, 'foo', 'right text'; |
2068 | is $dom->at('B')->{class}, 'two', 'right attribute'; |
2069 | is_deeply [sort keys %{$dom->at('a B')}], [qw(class test)], 'right attributes'; |
2070 | is $dom->find('a B c')->[0]->text, 'bar', 'right text'; |
2071 | is $dom->find('a B c')->[0]{id}, 'three', 'right attribute'; |
2072 | is_deeply [sort keys %{$dom->find('a B c')->[0]}], ['id'], 'right attributes'; |
2073 | is $dom->find('a B c')->[1]->text, 'baz', 'right text'; |
2074 | is $dom->find('a B c')->[1]{ID}, 'four', 'right attribute'; |
2075 | is_deeply [sort keys %{$dom->find('a B c')->[1]}], ['ID'], 'right attributes'; |
2076 | is $dom->find('a B c')->[2], undef, 'no result'; |
2077 | is $dom->find('a B c')->size, 2, 'right number of elements'; |
2078 | @results = (); |
2079 | $dom->find('a B c')->each(sub { push @results, $_->text }); |
2080 | is_deeply \@results, [qw(bar baz)], 'right results'; |
2081 | is $dom->find('a B c')->join("\n"), |
2082 | qq{<c id="three">bar</c>\n<c ID="four">baz</c>}, 'right result'; |
2083 | is_deeply [keys %$dom], [], 'root has no attributes'; |
2084 | is $dom->find('#nothing')->join, '', 'no result'; |
2085 | |
2086 | # Direct hash access to attributes in HTML mode |
2087 | $dom = DOM::Tiny->new(<<EOF); |
2088 | <a id="one"> |
2089 | <B class="two" test> |
2090 | foo |
2091 | <c id="three">bar</c> |
2092 | <c ID="four">baz</c> |
2093 | </B> |
2094 | </a> |
2095 | EOF |
2096 | ok !$dom->xml, 'XML mode not active'; |
2097 | is $dom->at('a')->{id}, 'one', 'right attribute'; |
2098 | is_deeply [sort keys %{$dom->at('a')}], ['id'], 'right attributes'; |
2099 | is $dom->at('a')->at('b')->text, 'foo', 'right text'; |
2100 | is $dom->at('b')->{class}, 'two', 'right attribute'; |
2101 | is_deeply [sort keys %{$dom->at('a b')}], [qw(class test)], 'right attributes'; |
2102 | is $dom->find('a b c')->[0]->text, 'bar', 'right text'; |
2103 | is $dom->find('a b c')->[0]{id}, 'three', 'right attribute'; |
2104 | is_deeply [sort keys %{$dom->find('a b c')->[0]}], ['id'], 'right attributes'; |
2105 | is $dom->find('a b c')->[1]->text, 'baz', 'right text'; |
2106 | is $dom->find('a b c')->[1]{id}, 'four', 'right attribute'; |
2107 | is_deeply [sort keys %{$dom->find('a b c')->[1]}], ['id'], 'right attributes'; |
2108 | is $dom->find('a b c')->[2], undef, 'no result'; |
2109 | is $dom->find('a b c')->size, 2, 'right number of elements'; |
2110 | @results = (); |
2111 | $dom->find('a b c')->each(sub { push @results, $_->text }); |
2112 | is_deeply \@results, [qw(bar baz)], 'right results'; |
2113 | is $dom->find('a b c')->join("\n"), |
2114 | qq{<c id="three">bar</c>\n<c id="four">baz</c>}, 'right result'; |
2115 | is_deeply [keys %$dom], [], 'root has no attributes'; |
2116 | is $dom->find('#nothing')->join, '', 'no result'; |
2117 | |
2118 | # Append and prepend content |
2119 | $dom = DOM::Tiny->new('<a><b>Test<c /></b></a>'); |
2120 | $dom->at('b')->append_content('<d />'); |
2121 | is $dom->children->[0]->tag, 'a', 'right tag'; |
2122 | is $dom->all_text, 'Test', 'right text'; |
2123 | is $dom->at('c')->parent->tag, 'b', 'right tag'; |
2124 | is $dom->at('d')->parent->tag, 'b', 'right tag'; |
2125 | $dom->at('b')->prepend_content('<e>DOM</e>'); |
2126 | is $dom->at('e')->parent->tag, 'b', 'right tag'; |
2127 | is $dom->all_text, 'DOM Test', 'right text'; |
2128 | |
2129 | # Wrap elements |
2130 | $dom = DOM::Tiny->new('<a>Test</a>'); |
c7cad649 |
2131 | is "$dom", '<a>Test</a>', 'right result'; |
d6512b50 |
2132 | is $dom->wrap('<b></b>')->type, 'root', 'right type'; |
c7cad649 |
2133 | is "$dom", '<a>Test</a>', 'no changes'; |
2134 | is $dom->at('a')->wrap('<b></b>')->type, 'tag', 'right type'; |
d6512b50 |
2135 | is "$dom", '<b><a>Test</a></b>', 'right result'; |
2136 | is $dom->at('b')->strip->at('a')->wrap('A')->tag, 'a', 'right tag'; |
2137 | is "$dom", '<a>Test</a>', 'right result'; |
2138 | is $dom->at('a')->wrap('<b></b>')->tag, 'a', 'right tag'; |
2139 | is "$dom", '<b><a>Test</a></b>', 'right result'; |
2140 | is $dom->at('a')->wrap('C<c><d>D</d><e>E</e></c>F')->parent->tag, 'd', |
2141 | 'right tag'; |
2142 | is "$dom", '<b>C<c><d>D<a>Test</a></d><e>E</e></c>F</b>', 'right result'; |
2143 | |
2144 | # Wrap content |
2145 | $dom = DOM::Tiny->new('<a>Test</a>'); |
2146 | is $dom->at('a')->wrap_content('A')->tag, 'a', 'right tag'; |
2147 | is "$dom", '<a>Test</a>', 'right result'; |
2148 | is $dom->wrap_content('<b></b>')->type, 'root', 'right type'; |
2149 | is "$dom", '<b><a>Test</a></b>', 'right result'; |
2150 | is $dom->at('b')->strip->at('a')->tag('e:a')->wrap_content('1<b c="d"></b>') |
2151 | ->tag, 'e:a', 'right tag'; |
2152 | is "$dom", '<e:a>1<b c="d">Test</b></e:a>', 'right result'; |
2153 | is $dom->at('a')->wrap_content('C<c><d>D</d><e>E</e></c>F')->parent->type, |
2154 | 'root', 'right type'; |
2155 | is "$dom", '<e:a>C<c><d>D1<b c="d">Test</b></d><e>E</e></c>F</e:a>', |
2156 | 'right result'; |
2157 | |
2158 | # Broken "div" in "td" |
2159 | $dom = DOM::Tiny->new(<<EOF); |
2160 | <table> |
2161 | <tr> |
2162 | <td><div id="A"></td> |
2163 | <td><div id="B"></td> |
2164 | </tr> |
2165 | </table> |
2166 | EOF |
2167 | is $dom->find('table tr td')->[0]->at('div')->{id}, 'A', 'right attribute'; |
2168 | is $dom->find('table tr td')->[1]->at('div')->{id}, 'B', 'right attribute'; |
2169 | is $dom->find('table tr td')->[2], undef, 'no result'; |
2170 | is $dom->find('table tr td')->size, 2, 'right number of elements'; |
2171 | is "$dom", <<EOF, 'right result'; |
2172 | <table> |
2173 | <tr> |
2174 | <td><div id="A"></div></td> |
2175 | <td><div id="B"></div></td> |
2176 | </tr> |
2177 | </table> |
2178 | EOF |
2179 | |
2180 | # Preformatted text |
2181 | $dom = DOM::Tiny->new(<<EOF); |
2182 | <div> |
2183 | looks |
2184 | <pre><code>like |
2185 | it |
2186 | really</code> |
2187 | </pre> |
2188 | works |
2189 | </div> |
2190 | EOF |
2191 | is $dom->text, '', 'no text'; |
2192 | is $dom->text(0), "\n", 'right text'; |
2193 | is $dom->all_text, "looks like\n it\n really\n works", 'right text'; |
2194 | is $dom->all_text(0), "\n looks\n like\n it\n really\n \n works\n\n", |
2195 | 'right text'; |
2196 | is $dom->at('div')->text, 'looks works', 'right text'; |
2197 | is $dom->at('div')->text(0), "\n looks\n \n works\n", 'right text'; |
2198 | is $dom->at('div')->all_text, "looks like\n it\n really\n works", |
2199 | 'right text'; |
2200 | is $dom->at('div')->all_text(0), |
2201 | "\n looks\n like\n it\n really\n \n works\n", 'right text'; |
2202 | is $dom->at('div pre')->text, "\n ", 'right text'; |
2203 | is $dom->at('div pre')->text(0), "\n ", 'right text'; |
2204 | is $dom->at('div pre')->all_text, "like\n it\n really\n ", 'right text'; |
2205 | is $dom->at('div pre')->all_text(0), "like\n it\n really\n ", 'right text'; |
2206 | is $dom->at('div pre code')->text, "like\n it\n really", 'right text'; |
2207 | is $dom->at('div pre code')->text(0), "like\n it\n really", 'right text'; |
2208 | is $dom->at('div pre code')->all_text, "like\n it\n really", 'right text'; |
2209 | is $dom->at('div pre code')->all_text(0), "like\n it\n really", |
2210 | 'right text'; |
2211 | |
2212 | # Form values |
2213 | $dom = DOM::Tiny->new(<<EOF); |
2214 | <form action="/foo"> |
2215 | <p>Test</p> |
2216 | <input type="text" name="a" value="A" /> |
4b5e2513 |
2217 | <input type="checkbox" name="q"> |
d6512b50 |
2218 | <input type="checkbox" checked name="b" value="B"> |
4b5e2513 |
2219 | <input type="radio" name="r"> |
d6512b50 |
2220 | <input type="radio" checked name="c" value="C"> |
4b5e2513 |
2221 | <input name="s"> |
2222 | <input type="checkbox" name="t" value=""> |
2223 | <input type=text name="u"> |
d6512b50 |
2224 | <select multiple name="f"> |
2225 | <option value="F">G</option> |
2226 | <optgroup> |
2227 | <option>H</option> |
2228 | <option selected>I</option> |
2229 | </optgroup> |
2230 | <option value="J" selected>K</option> |
2231 | </select> |
2232 | <select name="n"><option>N</option></select> |
2233 | <select multiple name="q"><option>Q</option></select> |
2234 | <select name="d"> |
2235 | <option selected>R</option> |
2236 | <option selected>D</option> |
2237 | </select> |
2238 | <textarea name="m">M</textarea> |
2239 | <button name="o" value="O">No!</button> |
2240 | <input type="submit" name="p" value="P" /> |
2241 | </form> |
2242 | EOF |
2243 | is $dom->at('p')->val, undef, 'no value'; |
2244 | is $dom->at('input')->val, 'A', 'right value'; |
2245 | is $dom->at('input:checked')->val, 'B', 'right value'; |
2246 | is $dom->at('input:checked[type=radio]')->val, 'C', 'right value'; |
2247 | is_deeply $dom->at('select')->val, ['I', 'J'], 'right values'; |
2248 | is $dom->at('select option')->val, 'F', 'right value'; |
2249 | is $dom->at('select optgroup option:not([selected])')->val, 'H', 'right value'; |
2250 | is $dom->find('select')->[1]->at('option')->val, 'N', 'right value'; |
2251 | is $dom->find('select')->[1]->val, undef, 'no value'; |
2252 | is_deeply $dom->find('select')->[2]->val, undef, 'no value'; |
2253 | is $dom->find('select')->[2]->at('option')->val, 'Q', 'right value'; |
2254 | is_deeply $dom->find('select')->last->val, 'D', 'right value'; |
2255 | is_deeply $dom->find('select')->last->at('option')->val, 'R', 'right value'; |
2256 | is $dom->at('textarea')->val, 'M', 'right value'; |
2257 | is $dom->at('button')->val, 'O', 'right value'; |
2258 | is $dom->find('form input')->last->val, 'P', 'right value'; |
4b5e2513 |
2259 | is $dom->at('input[name=q]')->val, 'on', 'right value'; |
2260 | is $dom->at('input[name=r]')->val, 'on', 'right value'; |
2261 | is $dom->at('input[name=s]')->val, undef, 'no value'; |
2262 | is $dom->at('input[name=t]')->val, '', 'right value'; |
2263 | is $dom->at('input[name=u]')->val, undef, 'no value'; |
d6512b50 |
2264 | |
2265 | # PoCo example with whitespace sensitive text |
2266 | $dom = DOM::Tiny->new(<<EOF); |
2267 | <?xml version="1.0" encoding="UTF-8"?> |
2268 | <response> |
2269 | <entry> |
2270 | <id>1286823</id> |
2271 | <displayName>Homer Simpson</displayName> |
2272 | <addresses> |
2273 | <type>home</type> |
2274 | <formatted><![CDATA[742 Evergreen Terrace |
2275 | Springfield, VT 12345 USA]]></formatted> |
2276 | </addresses> |
2277 | </entry> |
2278 | <entry> |
2279 | <id>1286822</id> |
2280 | <displayName>Marge Simpson</displayName> |
2281 | <addresses> |
2282 | <type>home</type> |
2283 | <formatted>742 Evergreen Terrace |
2284 | Springfield, VT 12345 USA</formatted> |
2285 | </addresses> |
2286 | </entry> |
2287 | </response> |
2288 | EOF |
2289 | is $dom->find('entry')->[0]->at('displayName')->text, 'Homer Simpson', |
2290 | 'right text'; |
2291 | is $dom->find('entry')->[0]->at('id')->text, '1286823', 'right text'; |
2292 | is $dom->find('entry')->[0]->at('addresses')->children('type')->[0]->text, |
2293 | 'home', 'right text'; |
2294 | is $dom->find('entry')->[0]->at('addresses formatted')->text, |
2295 | "742 Evergreen Terrace\nSpringfield, VT 12345 USA", 'right text'; |
2296 | is $dom->find('entry')->[0]->at('addresses formatted')->text(0), |
2297 | "742 Evergreen Terrace\nSpringfield, VT 12345 USA", 'right text'; |
2298 | is $dom->find('entry')->[1]->at('displayName')->text, 'Marge Simpson', |
2299 | 'right text'; |
2300 | is $dom->find('entry')->[1]->at('id')->text, '1286822', 'right text'; |
2301 | is $dom->find('entry')->[1]->at('addresses')->children('type')->[0]->text, |
2302 | 'home', 'right text'; |
2303 | is $dom->find('entry')->[1]->at('addresses formatted')->text, |
2304 | '742 Evergreen Terrace Springfield, VT 12345 USA', 'right text'; |
2305 | is $dom->find('entry')->[1]->at('addresses formatted')->text(0), |
2306 | "742 Evergreen Terrace\nSpringfield, VT 12345 USA", 'right text'; |
2307 | is $dom->find('entry')->[2], undef, 'no result'; |
2308 | is $dom->find('entry')->size, 2, 'right number of elements'; |
2309 | |
2310 | # Find attribute with hyphen in name and value |
2311 | $dom = DOM::Tiny->new(<<EOF); |
2312 | <html> |
2313 | <head><meta http-equiv="content-type" content="text/html"></head> |
2314 | </html> |
2315 | EOF |
2316 | is $dom->find('[http-equiv]')->[0]{content}, 'text/html', 'right attribute'; |
2317 | is $dom->find('[http-equiv]')->[1], undef, 'no result'; |
2318 | is $dom->find('[http-equiv="content-type"]')->[0]{content}, 'text/html', |
2319 | 'right attribute'; |
2320 | is $dom->find('[http-equiv="content-type"]')->[1], undef, 'no result'; |
2321 | is $dom->find('[http-equiv^="content-"]')->[0]{content}, 'text/html', |
2322 | 'right attribute'; |
2323 | is $dom->find('[http-equiv^="content-"]')->[1], undef, 'no result'; |
2324 | is $dom->find('head > [http-equiv$="-type"]')->[0]{content}, 'text/html', |
2325 | 'right attribute'; |
2326 | is $dom->find('head > [http-equiv$="-type"]')->[1], undef, 'no result'; |
2327 | |
2328 | # Find "0" attribute value |
2329 | $dom = DOM::Tiny->new(<<EOF); |
2330 | <a accesskey="0">Zero</a> |
2331 | <a accesskey="1">O&gTn>e</a> |
2332 | EOF |
2333 | is $dom->find('a[accesskey]')->[0]->text, 'Zero', 'right text'; |
2334 | is $dom->find('a[accesskey]')->[1]->text, 'O&gTn>e', 'right text'; |
2335 | is $dom->find('a[accesskey]')->[2], undef, 'no result'; |
2336 | is $dom->find('a[accesskey=0]')->[0]->text, 'Zero', 'right text'; |
2337 | is $dom->find('a[accesskey=0]')->[1], undef, 'no result'; |
2338 | is $dom->find('a[accesskey^=0]')->[0]->text, 'Zero', 'right text'; |
2339 | is $dom->find('a[accesskey^=0]')->[1], undef, 'no result'; |
2340 | is $dom->find('a[accesskey$=0]')->[0]->text, 'Zero', 'right text'; |
2341 | is $dom->find('a[accesskey$=0]')->[1], undef, 'no result'; |
2342 | is $dom->find('a[accesskey~=0]')->[0]->text, 'Zero', 'right text'; |
2343 | is $dom->find('a[accesskey~=0]')->[1], undef, 'no result'; |
2344 | is $dom->find('a[accesskey*=0]')->[0]->text, 'Zero', 'right text'; |
2345 | is $dom->find('a[accesskey*=0]')->[1], undef, 'no result'; |
2346 | is $dom->find('a[accesskey=1]')->[0]->text, 'O&gTn>e', 'right text'; |
2347 | is $dom->find('a[accesskey=1]')->[1], undef, 'no result'; |
2348 | is $dom->find('a[accesskey^=1]')->[0]->text, 'O&gTn>e', 'right text'; |
2349 | is $dom->find('a[accesskey^=1]')->[1], undef, 'no result'; |
2350 | is $dom->find('a[accesskey$=1]')->[0]->text, 'O&gTn>e', 'right text'; |
2351 | is $dom->find('a[accesskey$=1]')->[1], undef, 'no result'; |
2352 | is $dom->find('a[accesskey~=1]')->[0]->text, 'O&gTn>e', 'right text'; |
2353 | is $dom->find('a[accesskey~=1]')->[1], undef, 'no result'; |
2354 | is $dom->find('a[accesskey*=1]')->[0]->text, 'O&gTn>e', 'right text'; |
2355 | is $dom->find('a[accesskey*=1]')->[1], undef, 'no result'; |
2356 | is $dom->at('a[accesskey*="."]'), undef, 'no result'; |
2357 | |
2358 | # Empty attribute value |
2359 | $dom = DOM::Tiny->new(<<EOF); |
2360 | <foo bar=> |
2361 | test |
2362 | </foo> |
2363 | <bar>after</bar> |
2364 | EOF |
2365 | is $dom->tree->[0], 'root', 'right type'; |
2366 | is $dom->tree->[1][0], 'tag', 'right type'; |
2367 | is $dom->tree->[1][1], 'foo', 'right tag'; |
2368 | is_deeply $dom->tree->[1][2], {bar => ''}, 'right attributes'; |
2369 | is $dom->tree->[1][4][0], 'text', 'right type'; |
2370 | is $dom->tree->[1][4][1], "\n test\n", 'right text'; |
2371 | is $dom->tree->[3][0], 'tag', 'right type'; |
2372 | is $dom->tree->[3][1], 'bar', 'right tag'; |
2373 | is $dom->tree->[3][4][0], 'text', 'right type'; |
2374 | is $dom->tree->[3][4][1], 'after', 'right text'; |
2375 | is "$dom", <<EOF, 'right result'; |
2376 | <foo bar=""> |
2377 | test |
2378 | </foo> |
2379 | <bar>after</bar> |
2380 | EOF |
2381 | |
2382 | # Case-insensitive attribute values |
2383 | $dom = DOM::Tiny->new(<<EOF); |
2384 | <p class="foo">A</p> |
2385 | <p class="foo bAr">B</p> |
2386 | <p class="FOO">C</p> |
2387 | EOF |
2388 | is $dom->find('.foo')->map('text')->join(','), 'A,B', 'right result'; |
2389 | is $dom->find('.FOO')->map('text')->join(','), 'C', 'right result'; |
2390 | is $dom->find('[class=foo]')->map('text')->join(','), 'A', 'right result'; |
2391 | is $dom->find('[class=foo i]')->map('text')->join(','), 'A,C', 'right result'; |
2392 | is $dom->find('[class="foo" i]')->map('text')->join(','), 'A,C', 'right result'; |
2393 | is $dom->find('[class="foo bar"]')->size, 0, 'no results'; |
2394 | is $dom->find('[class="foo bar" i]')->map('text')->join(','), 'B', |
2395 | 'right result'; |
2396 | is $dom->find('[class~=foo]')->map('text')->join(','), 'A,B', 'right result'; |
2397 | is $dom->find('[class~=foo i]')->map('text')->join(','), 'A,B,C', |
2398 | 'right result'; |
2399 | is $dom->find('[class*=f]')->map('text')->join(','), 'A,B', 'right result'; |
2400 | is $dom->find('[class*=f i]')->map('text')->join(','), 'A,B,C', 'right result'; |
2401 | is $dom->find('[class^=F]')->map('text')->join(','), 'C', 'right result'; |
2402 | is $dom->find('[class^=F i]')->map('text')->join(','), 'A,B,C', 'right result'; |
2403 | is $dom->find('[class$=O]')->map('text')->join(','), 'C', 'right result'; |
2404 | is $dom->find('[class$=O i]')->map('text')->join(','), 'A,C', 'right result'; |
2405 | |
2406 | # Nested description lists |
2407 | $dom = DOM::Tiny->new(<<EOF); |
2408 | <dl> |
2409 | <dt>A</dt> |
2410 | <DD> |
2411 | <dl> |
2412 | <dt>B |
2413 | <dd>C |
2414 | </dl> |
2415 | </dd> |
2416 | </dl> |
2417 | EOF |
2418 | is $dom->find('dl > dd > dl > dt')->[0]->text, 'B', 'right text'; |
2419 | is $dom->find('dl > dd > dl > dd')->[0]->text, 'C', 'right text'; |
2420 | is $dom->find('dl > dt')->[0]->text, 'A', 'right text'; |
2421 | |
2422 | # Nested lists |
2423 | $dom = DOM::Tiny->new(<<EOF); |
2424 | <div> |
2425 | <ul> |
2426 | <li> |
2427 | A |
2428 | <ul> |
2429 | <li>B</li> |
2430 | C |
2431 | </ul> |
2432 | </li> |
2433 | </ul> |
2434 | </div> |
2435 | EOF |
2436 | is $dom->find('div > ul > li')->[0]->text, 'A', 'right text'; |
2437 | is $dom->find('div > ul > li')->[1], undef, 'no result'; |
2438 | is $dom->find('div > ul li')->[0]->text, 'A', 'right text'; |
2439 | is $dom->find('div > ul li')->[1]->text, 'B', 'right text'; |
2440 | is $dom->find('div > ul li')->[2], undef, 'no result'; |
2441 | is $dom->find('div > ul ul')->[0]->text, 'C', 'right text'; |
2442 | is $dom->find('div > ul ul')->[1], undef, 'no result'; |
2443 | |
2444 | # Unusual order |
2445 | $dom |
2446 | = DOM::Tiny->new('<a href="http://example.com" id="foo" class="bar">Ok!</a>'); |
2447 | is $dom->at('a:not([href$=foo])[href^=h]')->text, 'Ok!', 'right text'; |
2448 | is $dom->at('a:not([href$=example.com])[href^=h]'), undef, 'no result'; |
2449 | is $dom->at('a[href^=h]#foo.bar')->text, 'Ok!', 'right text'; |
2450 | is $dom->at('a[href^=h]#foo.baz'), undef, 'no result'; |
2451 | is $dom->at('a[href^=h]#foo:not(b)')->text, 'Ok!', 'right text'; |
2452 | is $dom->at('a[href^=h]#foo:not(a)'), undef, 'no result'; |
2453 | is $dom->at('[href^=h].bar:not(b)[href$=m]#foo')->text, 'Ok!', 'right text'; |
2454 | is $dom->at('[href^=h].bar:not(b)[href$=m]#bar'), undef, 'no result'; |
2455 | is $dom->at(':not(b)#foo#foo')->text, 'Ok!', 'right text'; |
2456 | is $dom->at(':not(b)#foo#bar'), undef, 'no result'; |
2457 | is $dom->at(':not([href^=h]#foo#bar)')->text, 'Ok!', 'right text'; |
2458 | is $dom->at(':not([href^=h]#foo#foo)'), undef, 'no result'; |
2459 | |
2460 | # Slash between attributes |
2461 | $dom = DOM::Tiny->new('<input /type=checkbox / value="/a/" checked/><br/>'); |
2462 | is_deeply $dom->at('input')->attr, |
2463 | {type => 'checkbox', value => '/a/', checked => undef}, 'right attributes'; |
2464 | is "$dom", '<input checked type="checkbox" value="/a/"><br>', 'right result'; |
2465 | |
2466 | # Dot and hash in class and id attributes |
2467 | $dom = DOM::Tiny->new('<p class="a#b.c">A</p><p id="a#b.c">B</p>'); |
2468 | is $dom->at('p.a\#b\.c')->text, 'A', 'right text'; |
2469 | is $dom->at(':not(p.a\#b\.c)')->text, 'B', 'right text'; |
2470 | is $dom->at('p#a\#b\.c')->text, 'B', 'right text'; |
2471 | is $dom->at(':not(p#a\#b\.c)')->text, 'A', 'right text'; |
2472 | |
2473 | # Extra whitespace |
2474 | $dom = DOM::Tiny->new('< span>a< /span><b >b</b><span >c</ span>'); |
2475 | is $dom->at('span')->text, 'a', 'right text'; |
2476 | is $dom->at('span + b')->text, 'b', 'right text'; |
2477 | is $dom->at('b + span')->text, 'c', 'right text'; |
2478 | is "$dom", '<span>a</span><b>b</b><span>c</span>', 'right result'; |
2479 | |
2480 | # Selectors with leading and trailing whitespace |
2481 | $dom = DOM::Tiny->new('<div id=foo><b>works</b></div>'); |
2482 | is $dom->at(' div b ')->text, 'works', 'right text'; |
2483 | is $dom->at(' :not( #foo ) ')->text, 'works', 'right text'; |
2484 | |
2485 | # "0" |
2486 | $dom = DOM::Tiny->new('0'); |
2487 | is "$dom", '0', 'right result'; |
2488 | $dom->append_content('☃'); |
2489 | is "$dom", '0☃', 'right result'; |
2490 | is $dom->parse('<!DOCTYPE 0>'), '<!DOCTYPE 0>', 'successful roundtrip'; |
2491 | is $dom->parse('<!--0-->'), '<!--0-->', 'successful roundtrip'; |
2492 | is $dom->parse('<![CDATA[0]]>'), '<![CDATA[0]]>', 'successful roundtrip'; |
2493 | is $dom->parse('<?0?>'), '<?0?>', 'successful roundtrip'; |
2494 | |
2495 | # Not self-closing |
2496 | $dom = DOM::Tiny->new('<div />< div ><pre />test</div >123'); |
2497 | is $dom->at('div > div > pre')->text, 'test', 'right text'; |
2498 | is "$dom", '<div><div><pre>test</pre></div>123</div>', 'right result'; |
2499 | $dom = DOM::Tiny->new('<p /><svg><circle /><circle /></svg>'); |
2500 | is $dom->find('p > svg > circle')->size, 2, 'two circles'; |
2501 | is "$dom", '<p><svg><circle></circle><circle></circle></svg></p>', |
2502 | 'right result'; |
2503 | |
2504 | # "image" |
2505 | $dom = DOM::Tiny->new('<image src="foo.png">test'); |
2506 | is $dom->at('img')->{src}, 'foo.png', 'right attribute'; |
2507 | is "$dom", '<img src="foo.png">test', 'right result'; |
2508 | |
2509 | # "title" |
2510 | $dom = DOM::Tiny->new('<title> <p>test<</title>'); |
2511 | is $dom->at('title')->text, ' <p>test<', 'right text'; |
2512 | is "$dom", '<title> <p>test<</title>', 'right result'; |
2513 | |
2514 | # "textarea" |
2515 | $dom = DOM::Tiny->new('<textarea id="a"> <p>test<</textarea>'); |
2516 | is $dom->at('textarea#a')->text, ' <p>test<', 'right text'; |
2517 | is "$dom", '<textarea id="a"> <p>test<</textarea>', 'right result'; |
2518 | |
2519 | # Comments |
2520 | $dom = DOM::Tiny->new(<<EOF); |
2521 | <!-- HTML5 --> |
2522 | <!-- bad idea -- HTML5 --> |
2523 | <!-- HTML4 -- > |
2524 | <!-- bad idea -- HTML4 -- > |
2525 | EOF |
2526 | is $dom->tree->[1][1], ' HTML5 ', 'right comment'; |
2527 | is $dom->tree->[3][1], ' bad idea -- HTML5 ', 'right comment'; |
2528 | is $dom->tree->[5][1], ' HTML4 ', 'right comment'; |
2529 | is $dom->tree->[7][1], ' bad idea -- HTML4 ', 'right comment'; |
2530 | |
0139fdcf |
2531 | SKIP: { |
ba909048 |
2532 | skip 'Regex subexpression recursion causes SIGSEGV on 5.8', 1 unless $] >= 5.010000; |
0139fdcf |
2533 | # Huge number of attributes |
2534 | $dom = DOM::Tiny->new('<div ' . ('a=b ' x 32768) . '>Test</div>'); |
2535 | is $dom->at('div[a=b]')->text, 'Test', 'right text'; |
2536 | } |
d6512b50 |
2537 | |
2538 | # Huge number of nested tags |
2539 | my $huge = ('<a>' x 100) . 'works' . ('</a>' x 100); |
2540 | $dom = DOM::Tiny->new($huge); |
2541 | is $dom->all_text, 'works', 'right text'; |
2542 | is "$dom", $huge, 'right result'; |
2543 | |
dbff35d4 |
2544 | # TO_JSON |
2545 | is +JSON::PP->new->convert_blessed->encode([DOM::Tiny->new('<a></a>')]), '["<a></a>"]', 'right result'; |
2546 | |
d6512b50 |
2547 | done_testing(); |