/[suikacvs]/markup/html/whatpm/Whatpm/ContentChecker.pm
Suika

Contents of /markup/html/whatpm/Whatpm/ContentChecker.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.54 - (hide annotations) (download)
Sun Nov 25 08:04:20 2007 UTC (18 years, 8 months ago) by wakaba
Branch: MAIN
Changes since 1.53: +9 -3 lines
++ whatpm/t/ChangeLog	25 Nov 2007 07:57:28 -0000
2007-11-25  Wakaba  <wakaba@suika.fam.cx>

	* content-model-1.dat, content-model-2.dat, content-model-3.dat,
	content-model-4.dat, table-1.dat: Test data are updated
	for the significant content check.

	* content-model-5.dat: New test data.

	* ContentChecker.t: New test data file is added.

++ whatpm/Whatpm/ChangeLog	25 Nov 2007 07:59:33 -0000
	* ContentChecker.pm ($AnyChecker): Old way to add child elements
	for checking had been used.

2007-11-25  Wakaba  <wakaba@suika.fam.cx>

++ whatpm/Whatpm/ContentChecker/ChangeLog	25 Nov 2007 08:00:46 -0000
	* HTML.pm: Support for checking for significant content (HTML5
	revision 1114).  Note that the current implementation has
	an issue on treatment for transparent or semi-transparent
	elements.

	* Atom.pm: Support for significant content checking (for composed
	HTML-Atom documents).

2007-11-25  Wakaba  <wakaba@suika.fam.cx>

1 wakaba 1.1 package Whatpm::ContentChecker;
2     use strict;
3 wakaba 1.54 our $VERSION=do{my @r=(q$Revision: 1.53 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
4 wakaba 1.1
5 wakaba 1.18 require Whatpm::URIChecker;
6    
7 wakaba 1.13 ## ISSUE: How XML and XML Namespaces conformance can (or cannot)
8     ## be applied to an in-memory representation (i.e. DOM)?
9    
10 wakaba 1.50 ## TODO: Conformance of an HTML document with non-html root element.
11    
12 wakaba 1.42 my $HTML_NS = q<http://www.w3.org/1999/xhtml>;
13 wakaba 1.9 my $XML_NS = q<http://www.w3.org/XML/1998/namespace>;
14     my $XMLNS_NS = q<http://www.w3.org/2000/xmlns/>;
15    
16 wakaba 1.42 my $Namespace = {
17 wakaba 1.43 q<http://www.w3.org/2005/Atom> => {module => 'Whatpm::ContentChecker::Atom'},
18 wakaba 1.42 $HTML_NS => {module => 'Whatpm::ContentChecker::HTML'},
19     $XML_NS => {loaded => 1},
20     $XMLNS_NS => {loaded => 1},
21     };
22    
23     our $AttrChecker = {
24 wakaba 1.9 $XML_NS => {
25 wakaba 1.13 space => sub {
26     my ($self, $attr) = @_;
27     my $value = $attr->value;
28     if ($value eq 'default' or $value eq 'preserve') {
29     #
30     } else {
31     ## NOTE: An XML "error"
32 wakaba 1.33 $self->{onerror}->(node => $attr, level => 'error',
33     type => 'invalid attribute value');
34 wakaba 1.13 }
35     },
36     lang => sub {
37 wakaba 1.35 my ($self, $attr) = @_;
38 wakaba 1.47 my $value = $attr->value;
39     if ($value eq '') {
40     #
41     } else {
42     require Whatpm::LangTag;
43     Whatpm::LangTag->check_rfc3066_language_tag ($value, sub {
44     my %opt = @_;
45     my $type = 'LangTag:'.$opt{type};
46     $type .= ':' . $opt{subtag} if defined $opt{subtag};
47     $self->{onerror}->(node => $attr, type => $type,
48     value => $opt{value}, level => $opt{level});
49     });
50     }
51    
52 wakaba 1.13 ## NOTE: "The values of the attribute are language identifiers
53     ## as defined by [IETF RFC 3066], Tags for the Identification
54     ## of Languages, or its successor; in addition, the empty string
55     ## may be specified." ("may" in lower case)
56 wakaba 1.47 ## NOTE: Is an RFC 3066-valid (but RFC 4647-invalid) language tag
57     ## allowed today?
58    
59     ## TODO: test data
60    
61 wakaba 1.35 if ($attr->owner_document->manakai_is_html) { # MUST NOT
62 wakaba 1.36 $self->{onerror}->(node => $attr, type => 'in HTML:xml:lang');
63 wakaba 1.35 ## TODO: Test data...
64     }
65 wakaba 1.13 },
66     base => sub {
67     my ($self, $attr) = @_;
68     my $value = $attr->value;
69     if ($value =~ /[^\x{0000}-\x{10FFFF}]/) { ## ISSUE: Should we disallow noncharacters?
70     $self->{onerror}->(node => $attr,
71 wakaba 1.33 type => 'invalid attribute value');
72 wakaba 1.13 }
73 wakaba 1.18 ## NOTE: Conformance to URI standard is not checked since there is
74     ## no author requirement on conformance in the XML Base specification.
75 wakaba 1.13 },
76     id => sub {
77     my ($self, $attr) = @_;
78     my $value = $attr->value;
79     $value =~ s/[\x09\x0A\x0D\x20]+/ /g;
80     $value =~ s/^\x20//;
81     $value =~ s/\x20$//;
82     ## TODO: NCName in XML 1.0 or 1.1
83     ## TODO: declared type is ID?
84 wakaba 1.33 if ($self->{id}->{$value}) { ## NOTE: An xml:id error
85     $self->{onerror}->(node => $attr, level => 'error',
86     type => 'duplicate ID');
87 wakaba 1.37 push @{$self->{id}->{$value}}, $attr;
88 wakaba 1.13 } else {
89 wakaba 1.37 $self->{id}->{$value} = [$attr];
90 wakaba 1.13 }
91     },
92 wakaba 1.9 },
93     $XMLNS_NS => {
94 wakaba 1.13 '' => sub {
95     my ($self, $attr) = @_;
96     my $ln = $attr->manakai_local_name;
97     my $value = $attr->value;
98     if ($value eq $XML_NS and $ln ne 'xml') {
99     $self->{onerror}
100 wakaba 1.33 ->(node => $attr, level => 'NC',
101     type => 'Reserved Prefixes and Namespace Names:=xml');
102 wakaba 1.13 } elsif ($value eq $XMLNS_NS) {
103     $self->{onerror}
104 wakaba 1.33 ->(node => $attr, level => 'NC',
105     type => 'Reserved Prefixes and Namespace Names:=xmlns');
106 wakaba 1.13 }
107     if ($ln eq 'xml' and $value ne $XML_NS) {
108     $self->{onerror}
109 wakaba 1.33 ->(node => $attr, level => 'NC',
110     type => 'Reserved Prefixes and Namespace Names:xmlns:xml=');
111 wakaba 1.13 } elsif ($ln eq 'xmlns') {
112     $self->{onerror}
113 wakaba 1.33 ->(node => $attr, level => 'NC',
114     type => 'Reserved Prefixes and Namespace Names:xmlns:xmlns=');
115 wakaba 1.13 }
116     ## TODO: If XML 1.0 and empty
117     },
118     xmlns => sub {
119     my ($self, $attr) = @_;
120     ## TODO: In XML 1.0, URI reference [RFC 3986] or an empty string
121     ## TODO: In XML 1.1, IRI reference [RFC 3987] or an empty string
122 wakaba 1.18 ## TODO: relative references are deprecated
123 wakaba 1.13 my $value = $attr->value;
124     if ($value eq $XML_NS) {
125     $self->{onerror}
126 wakaba 1.33 ->(node => $attr, level => 'NC',
127     type => 'Reserved Prefixes and Namespace Names:=xml');
128 wakaba 1.13 } elsif ($value eq $XMLNS_NS) {
129     $self->{onerror}
130 wakaba 1.33 ->(node => $attr, level => 'NC',
131     type => 'Reserved Prefixes and Namespace Names:=xmlns');
132 wakaba 1.13 }
133     },
134 wakaba 1.9 },
135     };
136    
137 wakaba 1.14 ## ISSUE: Should we really allow these attributes?
138 wakaba 1.13 $AttrChecker->{''}->{'xml:space'} = $AttrChecker->{$XML_NS}->{space};
139     $AttrChecker->{''}->{'xml:lang'} = $AttrChecker->{$XML_NS}->{lang};
140     $AttrChecker->{''}->{'xml:base'} = $AttrChecker->{$XML_NS}->{base};
141     $AttrChecker->{''}->{'xml:id'} = $AttrChecker->{$XML_NS}->{id};
142    
143 wakaba 1.3 ## ANY
144 wakaba 1.42 our $AnyChecker = sub {
145 wakaba 1.4 my ($self, $todo) = @_;
146     my $el = $todo->{node};
147     my $new_todos = [];
148 wakaba 1.3 my @nodes = (@{$el->child_nodes});
149     while (@nodes) {
150     my $node = shift @nodes;
151     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
152    
153     my $nt = $node->node_type;
154     if ($nt == 1) {
155     my $node_ns = $node->namespace_uri;
156     $node_ns = '' unless defined $node_ns;
157     my $node_ln = $node->manakai_local_name;
158     if ($self->{minuses}->{$node_ns}->{$node_ln}) {
159     $self->{onerror}->(node => $node, type => 'element not allowed');
160     }
161 wakaba 1.54 my ($sib, $ch) = $self->_check_get_children ($node, $todo);
162     unshift @nodes, @$sib;
163     push @$new_todos, @$ch;
164     } elsif ($nt == 3 or $nt == 4) {
165     if ($node->data =~ /[^\x09-\x0D\x20]/) {
166     $todo->{flag}->{has_descendant}->{significant} = 1;
167     }
168 wakaba 1.3 } elsif ($nt == 5) {
169     unshift @nodes, @{$node->child_nodes};
170     }
171     }
172 wakaba 1.4 return ($new_todos);
173 wakaba 1.3 }; # $AnyChecker
174    
175 wakaba 1.42 our $ElementDefault = {
176 wakaba 1.1 checker => sub {
177 wakaba 1.4 my ($self, $todo) = @_;
178 wakaba 1.33 $self->{onerror}->(node => $todo->{node}, level => 'unsupported',
179     type => 'element');
180 wakaba 1.4 return $AnyChecker->($self, $todo);
181 wakaba 1.1 },
182 wakaba 1.9 attrs_checker => sub {
183     my ($self, $todo) = @_;
184     for my $attr (@{$todo->{node}->attributes}) {
185     my $attr_ns = $attr->namespace_uri;
186     $attr_ns = '' unless defined $attr_ns;
187     my $attr_ln = $attr->manakai_local_name;
188     my $checker = $AttrChecker->{$attr_ns}->{$attr_ln}
189     || $AttrChecker->{$attr_ns}->{''};
190     if ($checker) {
191     $checker->($self, $attr);
192 wakaba 1.17 } else {
193 wakaba 1.33 $self->{onerror}->(node => $attr, level => 'unsupported',
194     type => 'attribute');
195 wakaba 1.9 }
196     }
197     },
198 wakaba 1.1 };
199    
200 wakaba 1.7 my $HTMLTransparentElements = {
201     $HTML_NS => {qw/ins 1 font 1 noscript 1/},
202 wakaba 1.29 ## NOTE: |html:noscript| is transparent if scripting is disabled
203     ## and not in |head|.
204 wakaba 1.7 };
205    
206 wakaba 1.42 our $Element = {};
207 wakaba 1.7
208 wakaba 1.42 sub check_document ($$$) {
209     my ($self, $doc, $onerror) = @_;
210     $self = bless {}, $self unless ref $self;
211     $self->{onerror} = $onerror;
212 wakaba 1.1
213 wakaba 1.48 $self->{must_level} = 'm';
214     $self->{fact_level} = 'f';
215     $self->{should_level} = 's';
216 wakaba 1.51 $self->{good_level} = 'w';
217 wakaba 1.48
218 wakaba 1.42 my $docel = $doc->document_element;
219     unless (defined $docel) {
220     ## ISSUE: Should we check content of Document node?
221     $onerror->(node => $doc, type => 'no document element');
222     ## ISSUE: Is this non-conforming (to what spec)? Or just a warning?
223     return {
224     class => {},
225     id => {}, table => [], term => {},
226     };
227 wakaba 1.1 }
228    
229 wakaba 1.42 ## ISSUE: Unexpanded entity references and HTML5 conformance
230 wakaba 1.1
231 wakaba 1.42 my $docel_nsuri = $docel->namespace_uri;
232     $docel_nsuri = '' unless defined $docel_nsuri;
233 wakaba 1.43 unless ($Namespace->{$docel_nsuri}->{loaded}) {
234     if ($Namespace->{$docel_nsuri}->{module}) {
235     eval qq{ require $Namespace->{$docel_nsuri}->{module} } or die $@;
236     } else {
237     $Namespace->{$docel_nsuri}->{loaded} = 1;
238     }
239     }
240 wakaba 1.42 my $docel_def = $Element->{$docel_nsuri}->{$docel->manakai_local_name} ||
241     $Element->{$docel_nsuri}->{''} ||
242     $ElementDefault;
243     if ($docel_def->{is_root}) {
244     #
245 wakaba 1.50 } elsif ($docel_def->{is_xml_root}) {
246     unless ($doc->manakai_is_html) {
247     #
248     } else {
249     $onerror->(node => $docel, type => 'element not allowed:root:xml');
250     }
251 wakaba 1.42 } else {
252 wakaba 1.49 $onerror->(node => $docel, type => 'element not allowed:root');
253 wakaba 1.1 }
254    
255 wakaba 1.42 ## TODO: Check for other items other than document element
256     ## (second (errorous) element, text nodes, PI nodes, doctype nodes)
257 wakaba 1.2
258 wakaba 1.51 my $return = $self->check_element ($docel, $onerror);
259    
260 wakaba 1.52 ## TODO: Test for these checks are necessary.
261 wakaba 1.51 my $charset_name = $doc->input_encoding;
262     if (defined $charset_name) {
263     require Message::Charset::Info;
264     my $charset = $Message::Charset::Info::IANACharset->{$charset_name};
265    
266     if ($doc->manakai_is_html and
267     not $doc->manakai_has_bom and
268     not defined $doc->manakai_charset) {
269     unless ($charset->{is_html_ascii_superset}) {
270     $onerror->(node => $doc, level => $self->{must_level},
271     type => 'non ascii superset:'.$charset_name);
272     }
273    
274     if (not $self->{has_charset} and
275     not $charset->{iana_names}->{'us-ascii'}) {
276     $onerror->(node => $doc, level => $self->{must_level},
277     type => 'no character encoding declaration:'.$charset_name);
278     }
279     }
280    
281     if ($charset->{iana_names}->{'utf-8'}) {
282     #
283     } elsif ($charset->{iana_names}->{'jis_x0212-1990'} or
284     $charset->{iana_names}->{'x-jis0208'} or
285     $charset->{iana_names}->{'utf-32'} or ## ISSUE: UTF-32BE? UTF-32LE?
286     $charset->{is_ebcdic_based}) {
287     $onerror->(node => $doc,
288     type => 'character encoding:'.$charset_name,
289     level => $self->{should_level});
290     } elsif ($charset->{iana_names}->{'cesu-8'} or
291     $charset->{iana_names}->{'utf-8'} or ## ISSUE: UNICODE-1-1-UTF-7?
292     $charset->{iana_names}->{'bocu-1'} or
293     $charset->{iana_names}->{'scsu'}) {
294     $onerror->(node => $doc,
295     type => 'character encoding:'.$charset_name,
296     level => $self->{must_level});
297     } else {
298     $onerror->(node => $doc,
299     type => 'character encoding:'.$charset_name,
300     level => $self->{good_level});
301     }
302 wakaba 1.52 } elsif ($doc->manakai_is_html) {
303     ## NOTE: MUST and SHOULD requirements above cannot be tested,
304     ## since the document has no input charset encoding information.
305     $onerror->(node => $doc,
306     type => 'character encoding:',
307     level => 'unsupported');
308 wakaba 1.51 }
309    
310     return $return;
311 wakaba 1.42 } # check_document
312 wakaba 1.1
313 wakaba 1.42 sub check_element ($$$) {
314     my ($self, $el, $onerror) = @_;
315     $self = bless {}, $self unless ref $self;
316     $self->{onerror} = $onerror;
317 wakaba 1.2
318 wakaba 1.48 $self->{must_level} = 'm';
319     $self->{fact_level} = 'f';
320     $self->{should_level} = 's';
321 wakaba 1.51 $self->{good_level} = 'w';
322 wakaba 1.48
323 wakaba 1.50 $self->{pluses} = {};
324 wakaba 1.42 $self->{minuses} = {};
325     $self->{id} = {};
326     $self->{term} = {};
327     $self->{usemap} = [];
328     $self->{contextmenu} = [];
329     $self->{map} = {};
330     $self->{menu} = {};
331     $self->{has_link_type} = {};
332 wakaba 1.46 #$self->{has_uri_attr};
333     #$self->{has_hyperlink_element};
334 wakaba 1.51 #$self->{has_charset};
335 wakaba 1.42 $self->{return} = {
336     class => {},
337     id => $self->{id}, table => [], term => $self->{term},
338     };
339 wakaba 1.4
340 wakaba 1.42 my @todo = ({type => 'element', node => $el});
341     while (@todo) {
342     my $todo = shift @todo;
343     if ($todo->{type} eq 'element') {
344     my $prefix = $todo->{node}->prefix;
345     if (defined $prefix and $prefix eq 'xmlns') {
346     $self->{onerror}
347     ->(node => $todo->{node}, level => 'NC',
348     type => 'Reserved Prefixes and Namespace Names:<xmlns:>');
349 wakaba 1.7 }
350 wakaba 1.42 my $nsuri = $todo->{node}->namespace_uri;
351     $nsuri = '' unless defined $nsuri;
352     unless ($Namespace->{$nsuri}->{loaded}) {
353     if ($Namespace->{$nsuri}->{module}) {
354     eval qq{ require $Namespace->{$nsuri}->{module} } or die $@;
355     } else {
356     $Namespace->{$nsuri}->{loaded} = 1;
357 wakaba 1.1 }
358     }
359 wakaba 1.42 my $ln = $todo->{node}->manakai_local_name;
360     my $eldef = $Element->{$nsuri}->{$ln} ||
361     $Element->{$nsuri}->{''} ||
362     $ElementDefault;
363     $eldef->{attrs_checker}->($self, $todo);
364     my ($new_todos) = $eldef->{checker}->($self, $todo);
365     unshift @todo, @$new_todos;
366     } elsif ($todo->{type} eq 'element-attributes') {
367     my $prefix = $todo->{node}->prefix;
368     if (defined $prefix and $prefix eq 'xmlns') {
369     $self->{onerror}
370     ->(node => $todo->{node}, level => 'NC',
371     type => 'Reserved Prefixes and Namespace Names:<xmlns:>');
372     }
373     my $nsuri = $todo->{node}->namespace_uri;
374     $nsuri = '' unless defined $nsuri;
375     unless ($Namespace->{$nsuri}->{loaded}) {
376     if ($Namespace->{$nsuri}->{module}) {
377     eval qq{ require $Namespace->{$nsuri}->{module} } or die $@;
378 wakaba 1.1 } else {
379 wakaba 1.42 $Namespace->{$nsuri}->{loaded} = 1;
380 wakaba 1.1 }
381     }
382 wakaba 1.9 my $ln = $todo->{node}->manakai_local_name;
383     my $eldef = $Element->{$nsuri}->{$ln} ||
384     $Element->{$nsuri}->{''} ||
385     $ElementDefault;
386     $eldef->{attrs_checker}->($self, $todo);
387 wakaba 1.53 } elsif ($todo->{type} eq 'descendant') {
388     for my $key (keys %{$todo->{errors}}) {
389     unless ($todo->{flag}->{has_descendant}->{$key}) {
390     $todo->{errors}->{$key}->($self, $todo);
391     }
392     for my $key (keys %{$todo->{old_values}}) {
393     $todo->{flag}->{has_descendant}->{$key}
394     ||= $todo->{old_values}->{$key};
395     }
396     }
397 wakaba 1.50 } elsif ($todo->{type} eq 'plus' or $todo->{type} eq 'minus') {
398 wakaba 1.4 $self->_remove_minuses ($todo);
399 wakaba 1.30 } elsif ($todo->{type} eq 'code') {
400     $todo->{code}->();
401     } else {
402     die "$0: Internal error: Unsupported checking action type |$todo->{type}|";
403 wakaba 1.4 }
404 wakaba 1.1 }
405 wakaba 1.17
406     for (@{$self->{usemap}}) {
407     unless ($self->{map}->{$_->[0]}) {
408     $self->{onerror}->(node => $_->[1], type => 'no referenced map');
409     }
410     }
411    
412 wakaba 1.32 for (@{$self->{contextmenu}}) {
413     unless ($self->{menu}->{$_->[0]}) {
414     $self->{onerror}->(node => $_->[1], type => 'no referenced menu');
415     }
416     }
417    
418 wakaba 1.50 delete $self->{pluses};
419 wakaba 1.17 delete $self->{minuses};
420     delete $self->{onerror};
421     delete $self->{id};
422     delete $self->{usemap};
423     delete $self->{map};
424 wakaba 1.33 return $self->{return};
425 wakaba 1.1 } # check_element
426    
427 wakaba 1.2 sub _add_minuses ($@) {
428     my $self = shift;
429     my $r = {};
430     for my $list (@_) {
431     for my $ns (keys %$list) {
432     for my $ln (keys %{$list->{$ns}}) {
433     unless ($self->{minuses}->{$ns}->{$ln}) {
434     $self->{minuses}->{$ns}->{$ln} = 1;
435     $r->{$ns}->{$ln} = 1;
436     }
437     }
438     }
439     }
440 wakaba 1.4 return {type => 'plus', list => $r};
441 wakaba 1.2 } # _add_minuses
442    
443 wakaba 1.50 sub _add_pluses ($@) {
444     my $self = shift;
445     my $r = {};
446     for my $list (@_) {
447     for my $ns (keys %$list) {
448     for my $ln (keys %{$list->{$ns}}) {
449     unless ($self->{pluses}->{$ns}->{$ln}) {
450     $self->{pluses}->{$ns}->{$ln} = 1;
451     $r->{$ns}->{$ln} = 1;
452     }
453     }
454     }
455     }
456     return {type => 'minus', list => $r};
457     } # _add_pluses
458    
459 wakaba 1.2 sub _remove_minuses ($$) {
460 wakaba 1.4 my ($self, $todo) = @_;
461 wakaba 1.50 if ($todo->{type} eq 'minus') {
462     for my $ns (keys %{$todo->{list}}) {
463     for my $ln (keys %{$todo->{list}->{$ns}}) {
464     delete $self->{pluses}->{$ns}->{$ln} if $todo->{list}->{$ns}->{$ln};
465     }
466 wakaba 1.2 }
467 wakaba 1.50 } elsif ($todo->{type} eq 'plus') {
468     for my $ns (keys %{$todo->{list}}) {
469     for my $ln (keys %{$todo->{list}->{$ns}}) {
470     delete $self->{minuses}->{$ns}->{$ln} if $todo->{list}->{$ns}->{$ln};
471     }
472     }
473     } else {
474     die "$0: Unknown +- type: $todo->{type}";
475 wakaba 1.2 }
476     1;
477     } # _remove_minuses
478    
479 wakaba 1.50 ## NOTE: Priority for "minuses" and "pluses" are currently left
480     ## undefined and implemented inconsistently; it is not a problem for
481     ## now, since no element belongs to both lists.
482    
483 wakaba 1.30 sub _check_get_children ($$$) {
484     my ($self, $node, $parent_todo) = @_;
485 wakaba 1.4 my $new_todos = [];
486 wakaba 1.2 my $sib = [];
487     TP: {
488     my $node_ns = $node->namespace_uri;
489     $node_ns = '' unless defined $node_ns;
490     my $node_ln = $node->manakai_local_name;
491 wakaba 1.45 if ($HTMLTransparentElements->{$node_ns}->{$node_ln}) {
492     if ($node_ns eq $HTML_NS and $node_ln eq 'noscript') {
493     if ($parent_todo->{flag}->{in_head}) {
494     #
495     } else {
496     my $end = $self->_add_minuses ({$HTML_NS, {noscript => 1}});
497     push @$sib, $end;
498    
499     unshift @$sib, @{$node->child_nodes};
500     push @$new_todos, {type => 'element-attributes', node => $node};
501     last TP;
502     }
503     } else {
504     unshift @$sib, @{$node->child_nodes};
505     push @$new_todos, {type => 'element-attributes', node => $node};
506     last TP;
507 wakaba 1.2 }
508     }
509 wakaba 1.8 if ($node_ns eq $HTML_NS and ($node_ln eq 'video' or $node_ln eq 'audio')) {
510 wakaba 1.2 if ($node->has_attribute_ns (undef, 'src')) {
511     unshift @$sib, @{$node->child_nodes};
512 wakaba 1.9 push @$new_todos, {type => 'element-attributes', node => $node};
513 wakaba 1.2 last TP;
514     } else {
515     my @cn = @{$node->child_nodes};
516     CN: while (@cn) {
517     my $cn = shift @cn;
518     my $cnt = $cn->node_type;
519     if ($cnt == 1) {
520 wakaba 1.8 my $cn_nsuri = $cn->namespace_uri;
521     $cn_nsuri = '' unless defined $cn_nsuri;
522     if ($cn_nsuri eq $HTML_NS and $cn->manakai_local_name eq 'source') {
523 wakaba 1.2 #
524     } else {
525     last CN;
526     }
527     } elsif ($cnt == 3 or $cnt == 4) {
528     if ($cn->data =~ /[^\x09-\x0D\x20]/) {
529     last CN;
530     }
531     }
532     } # CN
533     unshift @$sib, @cn;
534     }
535     }
536 wakaba 1.4 push @$new_todos, {type => 'element', node => $node};
537 wakaba 1.2 } # TP
538 wakaba 1.30
539     for my $new_todo (@$new_todos) {
540     $new_todo->{flag} = {%{$parent_todo->{flag} or {}}};
541     }
542    
543 wakaba 1.4 return ($sib, $new_todos);
544 wakaba 1.2 } # _check_get_children
545    
546 wakaba 1.44 =head1 LICENSE
547    
548     Copyright 2007 Wakaba <[email protected]>
549    
550     This library is free software; you can redistribute it
551     and/or modify it under the same terms as Perl itself.
552    
553     =cut
554    
555 wakaba 1.1 1;
556 wakaba 1.54 # $Date: 2007/11/25 03:46:07 $

[email protected]
ViewVC Help
Powered by ViewVC 1.1.24