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