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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (hide annotations) (download)
Sun Aug 5 09:24:56 2007 UTC (17 years, 3 months ago) by wakaba
Branch: MAIN
Changes since 1.2: +132 -23 lines
++ whatpm/Whatpm/ChangeLog	5 Aug 2007 09:23:31 -0000
	* H2H.pm: |b|, |i|, and |sub| are added to the
	list of allowed HTML elements.

2007-08-05  Wakaba  <wakaba@suika.fam.cx>

++ whatpm/Whatpm/ContentChecker/ChangeLog	5 Aug 2007 09:24:54 -0000
	* Atom.pm: |link|-related checks are added; |type|
	media type checks are added.  |hreflang| now warns
	as unimplemented.

2007-08-05  Wakaba  <wakaba@suika.fam.cx>

1 wakaba 1.1 package Whatpm::ContentChecker;
2     use strict;
3     require Whatpm::ContentChecker;
4    
5 wakaba 1.2 require Whatpm::URIChecker;
6    
7 wakaba 1.1 my $ATOM_NS = q<http://www.w3.org/2005/Atom>;
8 wakaba 1.3 my $LINK_REL = q<http://www.iana.org/assignments/relation/>;
9 wakaba 1.1
10     ## MUST be well-formed XML (RFC 4287 references XML 1.0 REC 20040204)
11    
12     ## NOTE: Commants and PIs are not explicitly allowed.
13    
14     our $AttrChecker;
15    
16     ## Any element MAY have xml:base, xml:lang
17     my $GetAtomAttrsChecker = sub {
18     my $element_specific_checker = shift;
19     return sub {
20     my ($self, $todo) = @_;
21     for my $attr (@{$todo->{node}->attributes}) {
22     my $attr_ns = $attr->namespace_uri;
23     $attr_ns = '' unless defined $attr_ns;
24     my $attr_ln = $attr->manakai_local_name;
25     my $checker;
26     if ($attr_ns eq '') {
27     $checker = $element_specific_checker->{$attr_ln};
28     } else {
29     $checker = $AttrChecker->{$attr_ns}->{$attr_ln}
30     || $AttrChecker->{$attr_ns}->{''};
31     }
32     if ($checker) {
33     $checker->($self, $attr, $todo);
34     } else {
35     $self->{onerror}->(node => $attr, level => 'unsupported',
36     type => 'attribute');
37     ## ISSUE: No comformance createria for unknown attributes in the spec
38     }
39     }
40     };
41     }; # $GetAtomAttrsChecker
42    
43     my $AtomTextConstruct = {
44     attrs_checker => $GetAtomAttrsChecker->({
45     type => sub { 1 }, # checked in |checker|
46     }),
47     checker => sub {
48     my ($self, $todo) = @_;
49    
50     my $attr = $todo->{node}->get_attribute_node_ns (undef, 'type');
51     my $value = 'text';
52     if ($attr) {
53     $value = $attr->value;
54     if ($value eq 'text' or $value eq 'html' or $value eq 'xhtml') {
55     # MUST
56     } else {
57     $self->{onerror}->(node => $attr, type => 'keyword:invalid');
58     }
59     # IMT MUST NOT be used
60     }
61    
62     if ($value eq 'text') {
63     my @nodes = (@{$todo->{node}->child_nodes});
64     my $new_todos = [];
65    
66     while (@nodes) {
67     my $node = shift @nodes;
68     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
69    
70     my $nt = $node->node_type;
71     if ($nt == 1) {
72     # MUST NOT
73     $self->{onerror}->(node => $node, type => 'element not allowed');
74     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
75     unshift @nodes, @$sib;
76     push @$new_todos, @$ch;
77     } elsif ($nt == 5) {
78     unshift @nodes, @{$node->child_nodes};
79     }
80     }
81    
82     return ($new_todos);
83     } elsif ($value eq 'html') {
84     my @nodes = (@{$todo->{node}->child_nodes});
85     my $new_todos = [];
86    
87     while (@nodes) {
88     my $node = shift @nodes;
89     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
90    
91     my $nt = $node->node_type;
92     if ($nt == 1) {
93     # MUST NOT
94     $self->{onerror}->(node => $node, type => 'element not allowed');
95     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
96     unshift @nodes, @$sib;
97     push @$new_todos, @$ch;
98     } elsif ($nt == 5) {
99     unshift @nodes, @{$node->child_nodes};
100     }
101     }
102    
103     ## TODO: SHOULD be suitable for handling as HTML [HTML4]
104     # markup MUST be escaped
105     ## TODO: HTML SHOULD be valid as if within <div>
106    
107     return ($new_todos);
108     } elsif ($value eq 'xhtml') {
109     my @nodes = (@{$todo->{node}->child_nodes});
110     my $new_todos = [];
111    
112     my $has_div;
113     while (@nodes) {
114     my $node = shift @nodes;
115     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
116    
117     my $nt = $node->node_type;
118     if ($nt == 1) {
119     # MUST
120     my $nsuri = $node->namespace_uri;
121     if (defined $nsuri and
122     $nsuri eq q<http://www.w3.org/1999/xhtml> and
123     $node->manakai_local_name eq 'div' and
124     not $has_div) {
125     ## TODO: SHOULD be suitable for handling as HTML [XHTML10]
126     $has_div = 1;
127     } else {
128     $self->{onerror}->(node => $node, type => 'element not allowed');
129     }
130     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
131     unshift @nodes, @$sib;
132     push @$new_todos, @$ch;
133     } elsif ($nt == 3 or $nt == 4) {
134     ## TODO: Are white spaces allowed?
135     $self->{onerror}->(node => $node, type => 'character not allowed');
136     } elsif ($nt == 5) {
137     unshift @nodes, @{$node->child_nodes};
138     }
139     }
140    
141     unless ($has_div) {
142     $self->{onerror}->(node => $todo->{node},
143     type => 'element missing:div');
144     }
145    
146     return ($new_todos);
147     }
148    
149     },
150     }; # $AtomTextConstruct
151    
152     my $AtomPersonConstruct = {
153     attrs_checker => $GetAtomAttrsChecker->({}),
154     checker => sub {
155     my ($self, $todo) = @_;
156    
157     my @nodes = (@{$todo->{node}->child_nodes});
158     my $new_todos = [];
159    
160     my $has_name;
161     my $has_uri;
162     my $has_email;
163     while (@nodes) {
164     my $node = shift @nodes;
165     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
166    
167     my $nt = $node->node_type;
168     if ($nt == 1) {
169     # MUST
170     my $nsuri = $node->namespace_uri;
171     $nsuri = '' unless defined $nsuri;
172     my $not_allowed;
173     if ($nsuri eq $ATOM_NS) {
174     my $ln = $node->manakai_local_name;
175     if ($ln eq 'name') {
176     unless ($has_name) {
177     $has_name = 1;
178     } else {
179     $not_allowed = 1;
180     }
181     } elsif ($ln eq 'uri') {
182     unless ($has_uri) {
183     $has_uri = 1;
184     } else {
185     $not_allowed = 1; # MUST NOT
186     }
187     } elsif ($ln eq 'email') {
188     unless ($has_email) {
189     $has_email = 1;
190     } else {
191     $not_allowed = 1; # MUST NOT
192     }
193     } else {
194     $not_allowed = 1;
195     }
196     } else {
197     ## TODO: extension element
198     $not_allowed = 1;
199     }
200     $self->{onerror}->(node => $node, type => 'element not allowed')
201     if $not_allowed;
202     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
203     unshift @nodes, @$sib;
204     push @$new_todos, @$ch;
205     } elsif ($nt == 3 or $nt == 4) {
206     ## TODO: Are white spaces allowed?
207     $self->{onerror}->(node => $node, type => 'character not allowed');
208     } elsif ($nt == 5) {
209     unshift @nodes, @{$node->child_nodes};
210     }
211     }
212    
213     unless ($has_name) { # MUST
214     $self->{onerror}->(node => $todo->{node},
215     type => 'element missing:atom.name');
216     }
217    
218     return ($new_todos);
219     },
220     }; # $AtomPersonConstruct
221    
222 wakaba 1.2 our $Element;
223    
224     $Element->{$ATOM_NS}->{name} = {
225     ## NOTE: Strictly speaking, structure and semantics for atom:name
226     ## element outside of Person construct is not defined.
227     attrs_checker => $GetAtomAttrsChecker->({}),
228     checker => sub {
229     my ($self, $todo) = @_;
230    
231     my @nodes = (@{$todo->{node}->child_nodes});
232     my $new_todos = [];
233    
234     while (@nodes) {
235     my $node = shift @nodes;
236     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
237    
238     my $nt = $node->node_type;
239     if ($nt == 1) {
240     ## NOTE: No constraint.
241     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
242     unshift @nodes, @$sib;
243     push @$new_todos, @$ch;
244     } elsif ($nt == 3 or $nt == 4) {
245     #
246     } elsif ($nt == 5) {
247     unshift @nodes, @{$node->child_nodes};
248     }
249     }
250    
251     return ($new_todos);
252     },
253     };
254    
255     $Element->{$ATOM_NS}->{uri} = {
256     ## NOTE: Strictly speaking, structure and semantics for atom:uri
257     ## element outside of Person construct is not defined.
258     attrs_checker => $GetAtomAttrsChecker->({}),
259     checker => sub {
260     my ($self, $todo) = @_;
261    
262     my @nodes = (@{$todo->{node}->child_nodes});
263     my $new_todos = [];
264    
265     my $s = '';
266     while (@nodes) {
267     my $node = shift @nodes;
268     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
269    
270     my $nt = $node->node_type;
271     if ($nt == 1) {
272     ## NOTE: Not explicitly disallowed.
273     $self->{onerror}->(node => $node, type => 'element not allowed');
274     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
275     unshift @nodes, @$sib;
276     push @$new_todos, @$ch;
277     } elsif ($nt == 3 or $nt == 4) {
278     $s .= $node->data;
279     } elsif ($nt == 5) {
280     unshift @nodes, @{$node->child_nodes};
281     }
282     }
283    
284     ## NOTE: There MUST NOT be any white space.
285     Whatpm::URIChecker->check_iri_reference ($s, sub {
286     my %opt = @_;
287     $self->{onerror}->(node => $todo->{node}, level => $opt{level},
288     type => 'URI::'.$opt{type}.
289     (defined $opt{position} ? ':'.$opt{position} : ''));
290     });
291    
292     return ($new_todos);
293     },
294     };
295    
296     $Element->{$ATOM_NS}->{email} = {
297     ## NOTE: Strictly speaking, structure and semantics for atom:email
298     ## element outside of Person construct is not defined.
299     attrs_checker => $GetAtomAttrsChecker->({}),
300     checker => sub {
301     my ($self, $todo) = @_;
302    
303     my @nodes = (@{$todo->{node}->child_nodes});
304     my $new_todos = [];
305    
306     my $s = '';
307     while (@nodes) {
308     my $node = shift @nodes;
309     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
310    
311     my $nt = $node->node_type;
312     if ($nt == 1) {
313     ## NOTE: Not explicitly disallowed.
314     $self->{onerror}->(node => $node, type => 'element not allowed');
315     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
316     unshift @nodes, @$sib;
317     push @$new_todos, @$ch;
318     } elsif ($nt == 3 or $nt == 4) {
319     $s .= $node->data;
320     } elsif ($nt == 5) {
321     unshift @nodes, @{$node->child_nodes};
322     }
323     }
324    
325     ## TODO: addr-spec
326     $self->{onerror}->(node => $todo->{node}, type => 'addr-spec',
327     level => 'unsupported');
328    
329     return ($new_todos);
330     },
331     };
332    
333 wakaba 1.1 ## MUST NOT be any white space
334     my $AtomDateConstruct = {
335     attrs_checker => $GetAtomAttrsChecker->({}),
336     checker => sub {
337     my ($self, $todo) = @_;
338    
339     my @nodes = (@{$todo->{node}->child_nodes});
340     my $new_todos = [];
341    
342     my $s = '';
343     while (@nodes) {
344     my $node = shift @nodes;
345     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
346    
347     my $nt = $node->node_type;
348     if ($nt == 1) {
349     ## NOTE: It does not explicitly say that there MUST NOT be any element.
350     $self->{onerror}->(node => $node, type => 'element not allowed');
351     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
352     unshift @nodes, @$sib;
353     push @$new_todos, @$ch;
354     } elsif ($nt == 3 or $nt == 4) {
355     $s .= $node->data;
356     } elsif ($nt == 5) {
357     unshift @nodes, @{$node->child_nodes};
358     }
359     }
360    
361     ## TODO: $s =~ MUST RFC 3339 date-time, uppercase T, Z
362     # SHOULD be accurate as possible
363    
364     return ($new_todos);
365     },
366     }; # $AtomDateConstruct
367    
368 wakaba 1.2 $Element->{$ATOM_NS}->{entry} = {
369 wakaba 1.1 is_root => 1,
370     attrs_checker => $GetAtomAttrsChecker->({}),
371     checker => sub {
372     my ($self, $todo) = @_;
373    
374     my @nodes = (@{$todo->{node}->child_nodes});
375     my $new_todos = [];
376    
377     ## TODO: MUST author+ unless (child::source/child::author)
378     ## or (parent::feed/child::author)
379    
380     my $has_element = {};
381     while (@nodes) {
382     my $node = shift @nodes;
383     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
384    
385     my $nt = $node->node_type;
386     if ($nt == 1) {
387     # MUST
388     my $nsuri = $node->namespace_uri;
389     $nsuri = '' unless defined $nsuri;
390     my $not_allowed;
391     if ($nsuri eq $ATOM_NS) {
392     my $ln = $node->manakai_local_name;
393     if ({ # MUST (0, 1)
394     content => 1,
395     id => 1,
396     published => 1,
397     rights => 1,
398     source => 1,
399     summary => 1,
400     ## TODO: MUST if child::content/@src | child::content/@type = IMT, !text/ !/xml !+xml
401     title => 1,
402     updated => 1,
403     }->{$ln}) {
404     unless ($has_element->{$ln}) {
405     $has_element->{$ln} = 1;
406     $not_allowed = $has_element->{entry};
407     } else {
408     $not_allowed = 1;
409     }
410     } elsif ($ln eq 'link') { # MAY
411 wakaba 1.3 if ($node->rel eq $LINK_REL . 'alternate') {
412     my $type = $node->get_attribute_ns (undef, 'type');
413     $type = '' unless defined $type;
414     my $hreflang = $node->get_attribute_ns (undef, 'hreflang');
415     $hreflang = '' unless defined $hreflang;
416     my $key = 'link:'.(defined $type ? ':'.$type : '').':'.
417     (defined $hreflang ? ':'.$hreflang : '');
418     unless ($has_element->{$key}) {
419     $has_element->{$key} = 1;
420     $has_element->{'link.alternate'} = 1;
421     } else {
422     $not_allowed = 1;
423     }
424     }
425    
426 wakaba 1.1 ## NOTE: MAY
427 wakaba 1.3 $not_allowed ||= $has_element->{entry};
428 wakaba 1.1 } elsif ({ # MAY
429     author => 1,
430     category => 1,
431     contributor => 1,
432     }->{$ln}) {
433     $not_allowed = $has_element->{entry};
434     } else {
435     $not_allowed = 1;
436     }
437     } else {
438     ## TODO: extension element
439     $not_allowed = 1;
440     }
441     $self->{onerror}->(node => $node, type => 'element not allowed')
442     if $not_allowed;
443     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
444     unshift @nodes, @$sib;
445     push @$new_todos, @$ch;
446     } elsif ($nt == 3 or $nt == 4) {
447     ## TODO: Are white spaces allowed?
448     $self->{onerror}->(node => $node, type => 'character not allowed');
449     } elsif ($nt == 5) {
450     unshift @nodes, @{$node->child_nodes};
451     }
452     }
453    
454     ## NOTE: metadata elements, followed by atom:entry* (no explicit MAY)
455    
456     ## TODO: If entry's with same id, then updated SHOULD be different
457    
458     unless ($has_element->{id}) { # MUST
459     $self->{onerror}->(node => $todo->{node},
460     type => 'element missing:atom.id');
461     }
462     unless ($has_element->{title}) { # MUST
463     $self->{onerror}->(node => $todo->{node},
464     type => 'element missing:atom.title');
465     }
466     unless ($has_element->{updated}) { # MUST
467     $self->{onerror}->(node => $todo->{node},
468     type => 'element missing:atom.updated');
469     }
470 wakaba 1.3 if (not $has_element->{content} and
471     not $has_element->{'link.alternate'}) {
472     $self->{onerror}->(node => $todo->{node},
473     type => 'element missing:atom.link.alternate');
474     }
475 wakaba 1.1
476     return ($new_todos);
477     },
478     };
479    
480     $Element->{$ATOM_NS}->{feed} = {
481     is_root => 1,
482     attrs_checker => $GetAtomAttrsChecker->({}),
483     checker => sub {
484     my ($self, $todo) = @_;
485    
486     my @nodes = (@{$todo->{node}->child_nodes});
487     my $new_todos = [];
488    
489     ## TODO: MUST author+ unless all entry child has author+.
490    
491     my $has_element = {};
492     while (@nodes) {
493     my $node = shift @nodes;
494     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
495    
496     my $nt = $node->node_type;
497     if ($nt == 1) {
498     my $nsuri = $node->namespace_uri;
499     $nsuri = '' unless defined $nsuri;
500     my $not_allowed;
501     if ($nsuri eq $ATOM_NS) {
502     my $ln = $node->manakai_local_name;
503     if ($ln eq 'entry') {
504     $has_element->{entry} = 1;
505     } elsif ({ # MUST (0, 1)
506     generator => 1,
507     icon => 1,
508     id => 1,
509     logo => 1,
510     rights => 1,
511     subtitle => 1,
512     title => 1,
513     updated => 1,
514     }->{$ln}) {
515     unless ($has_element->{$ln}) {
516     $has_element->{$ln} = 1;
517     $not_allowed = $has_element->{entry};
518     } else {
519     $not_allowed = 1;
520     }
521 wakaba 1.3 } elsif ($ln eq 'link') {
522     my $rel = $node->rel;
523     if ($rel eq $LINK_REL . 'alternate') {
524     my $type = $node->get_attribute_ns (undef, 'type');
525     $type = '' unless defined $type;
526     my $hreflang = $node->get_attribute_ns (undef, 'hreflang');
527     $hreflang = '' unless defined $hreflang;
528     my $key = 'link:'.(defined $type ? ':'.$type : '').':'.
529     (defined $hreflang ? ':'.$hreflang : '');
530     unless ($has_element->{$key}) {
531     $has_element->{$key} = 1;
532     } else {
533     $not_allowed = 1;
534     }
535     } elsif ($rel eq $LINK_REL . 'self') {
536     $has_element->{'link.self'} = 1;
537     }
538    
539     ## NOTE: MAY
540 wakaba 1.1 $not_allowed = $has_element->{entry};
541     } elsif ({ # MAY
542     author => 1,
543     category => 1,
544     contributor => 1,
545     }->{$ln}) {
546     $not_allowed = $has_element->{entry};
547     } else {
548     $not_allowed = 1;
549     }
550     } else {
551     ## TODO: extension element
552     $not_allowed = 1;
553     }
554     $self->{onerror}->(node => $node, type => 'element not allowed')
555     if $not_allowed;
556     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
557     unshift @nodes, @$sib;
558     push @$new_todos, @$ch;
559     } elsif ($nt == 3 or $nt == 4) {
560     ## TODO: Are white spaces allowed?
561     $self->{onerror}->(node => $node, type => 'character not allowed');
562     } elsif ($nt == 5) {
563     unshift @nodes, @{$node->child_nodes};
564     }
565     }
566    
567     ## NOTE: metadata elements, followed by atom:entry* (no explicit MAY)
568    
569     ## TODO: If entry's with same id, then updated SHOULD be different
570    
571     unless ($has_element->{id}) { # MUST
572     $self->{onerror}->(node => $todo->{node},
573     type => 'element missing:atom.id');
574     }
575     unless ($has_element->{title}) { # MUST
576     $self->{onerror}->(node => $todo->{node},
577     type => 'element missing:atom.title');
578     }
579     unless ($has_element->{updated}) { # MUST
580     $self->{onerror}->(node => $todo->{node},
581     type => 'element missing:atom.updated');
582     }
583 wakaba 1.3 unless ($has_element->{'link.self'}) {
584     $self->{onerror}->(node => $todo->{node}, level => 's',
585     type => 'child element missing:atom.link.self');
586     }
587 wakaba 1.1
588     return ($new_todos);
589     },
590     };
591    
592     $Element->{$ATOM_NS}->{content} = {
593     attrs_checker => $GetAtomAttrsChecker->({
594     src => sub { 1 }, # checked in |checker|
595     type => sub { 1 }, # checked in |checker|
596     }),
597     checker => sub {
598     my ($self, $todo) = @_;
599    
600     my $attr = $todo->{node}->get_attribute_node_ns (undef, 'type');
601     my $src_attr = $todo->{node}->get_attribute_node_ns (undef, 'src');
602     my $value;
603     if ($attr) {
604     $value = $attr->value;
605     if ($value eq 'text' or $value eq 'html' or $value eq 'xhtml') {
606     # MUST
607     } else {
608 wakaba 1.3 ## NOTE: MUST be a MIME media type. What is "MIME media type"?
609     my $value = $attr->value;
610     my $lws0 = qr/(?>(?>\x0D\x0A)?[\x09\x20])*/;
611     my $token = qr/[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7E]+/;
612     my $qs = qr/"(?>[\x00-\x0C\x0E-\x21\x23-\x5B\x5D-\x7E]|\x0D\x0A[\x09\x20]|\x5C[\x00-\x7F])*"/;
613     if ($value =~ m#\A$lws0($token)$lws0/$lws0($token)$lws0((?>;$lws0$token$lws0=$lws0(?>$token|$qs)$lws0)*)\z#) {
614     my @type = ($1, $2);
615     my $param = $3;
616     while ($param =~ s/^;$lws0($token)$lws0=$lws0(?>($token)|($qs))$lws0//) {
617     if (defined $2) {
618     push @type, $1 => $2;
619     } else {
620     my $n = $1;
621     my $v = $2;
622     $v =~ s/\\(.)/$1/gs;
623     push @type, $n => $v;
624     }
625     }
626     require Whatpm::IMTChecker;
627     Whatpm::IMTChecker->check_imt (sub {
628     my %opt = @_;
629     $self->{onerror}->(node => $attr, level => $opt{level},
630     type => 'IMT:'.$opt{type});
631     }, @type);
632     } else {
633     $self->{onerror}->(node => $attr, type => 'IMT:syntax error');
634     }
635 wakaba 1.1 }
636     } elsif ($src_attr) {
637     $value = '';
638     $self->{onerror}->(node => $todo->{node},
639     type => 'attribute missing:type', level => 's');
640     } else {
641     $value = 'text';
642     }
643    
644     ## TODO: This implementation is not optimal.
645    
646     if ($src_attr) {
647 wakaba 1.2 ## NOTE: There MUST NOT be any white space.
648     Whatpm::URIChecker->check_iri_reference ($src_attr->value, sub {
649     my %opt = @_;
650     $self->{onerror}->(node => $todo->{node}, level => $opt{level},
651     type => 'URI::'.$opt{type}.
652     (defined $opt{position} ? ':'.$opt{position} : ''));
653     });
654 wakaba 1.1
655     ## NOTE: If @src, the element MUST be empty. What is "empty"?
656     ## Is |<e><!----></e>| empty? |<e>&e;</e>| where |&e;| has
657     ## empty replacement tree shuld be empty, since Atom is defined
658     ## in terms of XML Information Set where entities are expanded.
659     ## (but what if |&e;| is an unexpanded entity?)
660     }
661    
662     if ($value eq 'text') {
663     $self->{onerror}->(node => $attr, type => 'not IMT') if $src_attr;
664    
665     my @nodes = (@{$todo->{node}->child_nodes});
666     my $new_todos = [];
667    
668     while (@nodes) {
669     my $node = shift @nodes;
670     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
671    
672     my $nt = $node->node_type;
673     if ($nt == 1) {
674     # MUST NOT
675     $self->{onerror}->(node => $node, type => 'element not allowed');
676     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
677     unshift @nodes, @$sib;
678     push @$new_todos, @$ch;
679     } elsif ($nt == 3 or $nt == 4) {
680     $self->{onerror}->(node => $node, type => 'character not allowed')
681     if $src_attr;
682     } elsif ($nt == 5) {
683     unshift @nodes, @{$node->child_nodes};
684     }
685     }
686    
687     return ($new_todos);
688     } elsif ($value eq 'html') {
689     $self->{onerror}->(node => $attr, type => 'not IMT') if $src_attr;
690    
691     my @nodes = (@{$todo->{node}->child_nodes});
692     my $new_todos = [];
693    
694     while (@nodes) {
695     my $node = shift @nodes;
696     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
697    
698     my $nt = $node->node_type;
699     if ($nt == 1) {
700     # MUST NOT
701     $self->{onerror}->(node => $node, type => 'element not allowed');
702     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
703     unshift @nodes, @$sib;
704     push @$new_todos, @$ch;
705     } elsif ($nt == 3 or $nt == 4) {
706     $self->{onerror}->(node => $node, type => 'character not allowed')
707     if $src_attr;
708     } elsif ($nt == 5) {
709     unshift @nodes, @{$node->child_nodes};
710     }
711     }
712    
713     ## TODO: SHOULD be suitable for handling as HTML [HTML4]
714     # markup MUST be escaped
715     ## TODO: HTML SHOULD be valid as if within <div>
716    
717     return ($new_todos);
718     } elsif ($value eq 'xhtml') {
719     $self->{onerror}->(node => $attr, type => 'not IMT') if $src_attr;
720    
721     my @nodes = (@{$todo->{node}->child_nodes});
722     my $new_todos = [];
723    
724     my $has_div;
725     while (@nodes) {
726     my $node = shift @nodes;
727     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
728    
729     my $nt = $node->node_type;
730     if ($nt == 1) {
731     # MUST
732     my $nsuri = $node->namespace_uri;
733     if (defined $nsuri and
734     $nsuri eq q<http://www.w3.org/1999/xhtml> and
735     $node->manakai_local_name eq 'div' and
736     not $has_div) {
737     ## TODO: SHOULD be suitable for handling as HTML [XHTML10]
738     $has_div = 1;
739     $self->{onerror}->(node => $node, type => 'element not allowed')
740     if $src_attr;
741     } else {
742     $self->{onerror}->(node => $node, type => 'element not allowed');
743     }
744     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
745     unshift @nodes, @$sib;
746     push @$new_todos, @$ch;
747     } elsif ($nt == 3 or $nt == 4) {
748     ## TODO: Are white spaces allowed?
749     $self->{onerror}->(node => $node, type => 'character not allowed');
750     } elsif ($nt == 5) {
751     unshift @nodes, @{$node->child_nodes};
752     }
753     }
754    
755     unless ($has_div) {
756     $self->{onerror}->(node => $todo->{node},
757     type => 'element missing:div');
758     }
759    
760     return ($new_todos);
761     } elsif ($value =~ m![+/][Xx][Mm][Ll]\z!) {
762     ## ISSUE: There is no definition for "XML media type" in RFC 3023.
763     ## Is |application/xml-dtd| an XML media type?
764    
765     my @nodes = (@{$todo->{node}->child_nodes});
766     my $new_todos = [];
767    
768     while (@nodes) {
769     my $node = shift @nodes;
770     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
771    
772     my $nt = $node->node_type;
773     if ($nt == 1) {
774     ## MAY contain elements
775     $self->{onerror}->(node => $node, type => 'element not allowed')
776     if $src_attr;
777     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
778     unshift @nodes, @$sib;
779     push @$new_todos, @$ch;
780     } elsif ($nt == 3 or $nt == 4) {
781     ## TODO: Are white spaces allowed?
782     $self->{onerror}->(node => $node, type => 'character not allowed');
783     } elsif ($nt == 5) {
784     unshift @nodes, @{$node->child_nodes};
785     }
786     }
787    
788 wakaba 1.3 ## NOTE: SHOULD be suitable for handling as $value.
789 wakaba 1.1 ## If no @src, this would normally mean it contains a
790     ## single child element that would serve as the root element.
791 wakaba 1.3 $self->{onerror}->(node => $todo->{node}, level => 'unsupported',
792     type => 'content:'.$value);
793 wakaba 1.1
794     return ($new_todos);
795     } elsif ($value =~ m!^[Tt][Ee][Xx][Tt]/!) {
796     my @nodes = (@{$todo->{node}->child_nodes});
797     my $new_todos = [];
798    
799     while (@nodes) {
800     my $node = shift @nodes;
801     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
802    
803     my $nt = $node->node_type;
804     if ($nt == 1) {
805     # MUST NOT
806     $self->{onerror}->(node => $node, type => 'element not allowed');
807     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
808     unshift @nodes, @$sib;
809     push @$new_todos, @$ch;
810     } elsif ($nt == 3 or $nt == 4) {
811     $self->{onerror}->(node => $node, type => 'character not allowed')
812     if $src_attr;
813     } elsif ($nt == 5) {
814     unshift @nodes, @{$node->child_nodes};
815     }
816     }
817    
818     ## NOTE: No further restriction (such as to conform to the type).
819    
820     return ($new_todos);
821     } else {
822     my @nodes = (@{$todo->{node}->child_nodes});
823     my $new_todos = [];
824    
825     if ($value =~ m!^(?>message|multipart)/!i) { # MUST NOT
826     $self->{onerror}->(node => $attr, type => 'IMT:composite');
827     }
828    
829     my $s = '';
830     while (@nodes) {
831     my $node = shift @nodes;
832     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
833    
834     my $nt = $node->node_type;
835     if ($nt == 1) {
836     ## not explicitly disallowed
837     $self->{onerror}->(node => $node, type => 'element not allowed');
838     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
839     unshift @nodes, @$sib;
840     push @$new_todos, @$ch;
841     } elsif ($nt == 3 or $nt == 4) {
842     $s .= $node->data;
843     $self->{onerror}->(node => $node, type => 'character not allowed')
844     if $src_attr;
845     } elsif ($nt == 5) {
846     unshift @nodes, @{$node->child_nodes};
847     }
848     }
849    
850     ## TODO: $s = valid Base64ed [RFC 3548] where
851     ## MAY leading and following "white space" (what?)
852     ## and lines separated by a single U+000A
853 wakaba 1.3
854     ## NOTE: SHOULD be suitable for the indicated media type.
855     $self->{onerror}->(node => $todo->{node}, level => 'unsupported',
856     type => 'content:'.$value);
857 wakaba 1.1
858     return ($new_todos);
859     }
860     },
861     };
862    
863     $Element->{$ATOM_NS}->{author} = $AtomPersonConstruct;
864    
865     $Element->{$ATOM_NS}->{category} = {
866     attrs_checker => $GetAtomAttrsChecker->({
867     label => sub { 1 }, # no value constraint
868 wakaba 1.2 scheme => sub { # NOTE: No MUST.
869     my ($self, $attr) = @_;
870     ## NOTE: There MUST NOT be any white space.
871     Whatpm::URIChecker->check_iri ($attr->value, sub {
872     my %opt = @_;
873     $self->{onerror}->(node => $attr, level => $opt{level},
874     type => 'URI::'.$opt{type}.
875     (defined $opt{position} ? ':'.$opt{position} : ''));
876     });
877     },
878 wakaba 1.1 term => sub { 1 }, # no value constraint
879     }),
880     checker => sub {
881     my ($self, $todo) = @_;
882    
883     unless ($todo->{node}->has_attribute_ns (undef, 'term')) {
884     $self->{onerror}->(node => $todo->{node},
885     type => 'attribute missing:term');
886     }
887    
888     my @nodes = (@{$todo->{node}->child_nodes});
889     my $new_todos = [];
890    
891     while (@nodes) {
892     my $node = shift @nodes;
893     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
894    
895     my $nt = $node->node_type;
896     if ($nt == 1) {
897     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
898     unshift @nodes, @$sib;
899     push @$new_todos, @$ch;
900     } elsif ($nt == 3 or $nt == 4) {
901     #
902     } elsif ($nt == 5) {
903     unshift @nodes, @{$node->child_nodes};
904     }
905     }
906    
907     return ($new_todos);
908     },
909     };
910    
911     $Element->{$ATOM_NS}->{contributor} = $AtomPersonConstruct;
912    
913     $Element->{$ATOM_NS}->{generator} = {
914     attrs_checker => $GetAtomAttrsChecker->({
915 wakaba 1.2 uri => sub { # MUST
916     my ($self, $attr) = @_;
917     ## NOTE: There MUST NOT be any white space.
918     Whatpm::URIChecker->check_iri_reference ($attr->value, sub {
919     my %opt = @_;
920     $self->{onerror}->(node => $attr, level => $opt{level},
921     type => 'URI::'.$opt{type}.
922     (defined $opt{position} ? ':'.$opt{position} : ''));
923     });
924     ## NOTE: Dereferencing SHOULD produce a representation
925     ## that is relevant to the agent.
926     },
927 wakaba 1.1 version => sub { 1 }, # no value constraint
928     }),
929     checker => sub {
930     my ($self, $todo) = @_;
931    
932     my @nodes = (@{$todo->{node}->child_nodes});
933     my $new_todos = [];
934    
935     while (@nodes) {
936     my $node = shift @nodes;
937     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
938    
939     my $nt = $node->node_type;
940     if ($nt == 1) {
941     ## not explicitly disallowed
942     $self->{onerror}->(node => $node, type => 'element not allowed');
943     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
944     unshift @nodes, @$sib;
945     push @$new_todos, @$ch;
946     } elsif ($nt == 3 or $nt == 4) {
947     ## MUST be a string that is a human-readable name for
948     ## the generating agent
949     } elsif ($nt == 5) {
950     unshift @nodes, @{$node->child_nodes};
951     }
952     }
953    
954     return ($new_todos);
955     },
956     };
957    
958     $Element->{$ATOM_NS}->{icon} = {
959     attrs_checker => $GetAtomAttrsChecker->({}),
960     checker => sub {
961     my ($self, $todo) = @_;
962    
963     my @nodes = (@{$todo->{node}->child_nodes});
964     my $new_todos = [];
965    
966 wakaba 1.2 my $s = '';
967 wakaba 1.1 while (@nodes) {
968     my $node = shift @nodes;
969     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
970    
971     my $nt = $node->node_type;
972     if ($nt == 1) {
973     ## not explicitly disallowed
974     $self->{onerror}->(node => $node, type => 'element not allowed');
975     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
976     unshift @nodes, @$sib;
977     push @$new_todos, @$ch;
978     } elsif ($nt == 3 or $nt == 4) {
979 wakaba 1.2 $s .= $node->data;
980 wakaba 1.1 } elsif ($nt == 5) {
981     unshift @nodes, @{$node->child_nodes};
982     }
983     }
984    
985 wakaba 1.2 ## NOTE: No MUST.
986     ## NOTE: There MUST NOT be any white space.
987     Whatpm::URIChecker->check_iri_reference ($s, sub {
988     my %opt = @_;
989     $self->{onerror}->(node => $todo->{node}, level => $opt{level},
990     type => 'URI::'.$opt{type}.
991     (defined $opt{position} ? ':'.$opt{position} : ''));
992     });
993    
994 wakaba 1.1 ## NOTE: Image SHOULD be 1:1 and SHOULD be small
995    
996     return ($new_todos);
997     },
998     };
999    
1000     $Element->{$ATOM_NS}->{id} = {
1001     attrs_checker => $GetAtomAttrsChecker->({}),
1002     checker => sub {
1003     my ($self, $todo) = @_;
1004    
1005     my @nodes = (@{$todo->{node}->child_nodes});
1006     my $new_todos = [];
1007 wakaba 1.2
1008     my $s = '';
1009     while (@nodes) {
1010     my $node = shift @nodes;
1011     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
1012    
1013     my $nt = $node->node_type;
1014     if ($nt == 1) {
1015     ## not explicitly disallowed
1016     $self->{onerror}->(node => $node, type => 'element not allowed');
1017     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
1018     unshift @nodes, @$sib;
1019     push @$new_todos, @$ch;
1020     } elsif ($nt == 3 or $nt == 4) {
1021     $s .= $node->data;
1022     } elsif ($nt == 5) {
1023     unshift @nodes, @{$node->child_nodes};
1024     }
1025     }
1026    
1027     ## NOTE: There MUST NOT be any white space.
1028     Whatpm::URIChecker->check_iri ($s, sub { # MUST
1029     my %opt = @_;
1030     $self->{onerror}->(node => $todo->{node}, level => $opt{level},
1031     type => 'URI::'.$opt{type}.
1032     (defined $opt{position} ? ':'.$opt{position} : ''));
1033     });
1034     ## TODO: SHOULD be normalized
1035    
1036     return ($new_todos);
1037     },
1038     };
1039    
1040     $Element->{$ATOM_NS}->{link} = {
1041     attrs_checker => $GetAtomAttrsChecker->({
1042     href => sub {
1043     my ($self, $attr) = @_;
1044     ## NOTE: There MUST NOT be any white space.
1045     Whatpm::URIChecker->check_iri_reference ($attr->value, sub {
1046     my %opt = @_;
1047     $self->{onerror}->(node => $attr, level => $opt{level},
1048     type => 'URI::'.$opt{type}.
1049     (defined $opt{position} ? ':'.$opt{position} : ''));
1050     });
1051     },
1052 wakaba 1.3 hreflang => sub {
1053     my ($self, $attr) = @_;
1054     ## TODO: MUST be an RFC 3066 language tag
1055     $self->{onerror}->(node => $attr, level => 'unsupported',
1056     type => 'language tag');
1057     },
1058 wakaba 1.2 length => sub { }, # No MUST; in octets.
1059     rel => sub { # MUST
1060     my ($self, $attr) = @_;
1061     my $value = $attr->value;
1062     if ($value =~ /\A(?>[0-9A-Za-z._~!\$&'()*+,;=\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}-]|%[0-9A-Fa-f][0-9A-Fa-f]|\@)+\z/) {
1063 wakaba 1.3 $value = $LINK_REL . $value;
1064 wakaba 1.2 }
1065    
1066     ## NOTE: There MUST NOT be any white space.
1067     Whatpm::URIChecker->check_iri ($value, sub {
1068     my %opt = @_;
1069     $self->{onerror}->(node => $attr, level => $opt{level},
1070     type => 'URI::'.$opt{type}.
1071     (defined $opt{position} ? ':'.$opt{position} : ''));
1072     });
1073    
1074     ## TODO: Warn if unregistered
1075     },
1076 wakaba 1.3 type => sub {
1077     ## NOTE: MUST be a MIME media type. What is "MIME media type"?
1078     my ($self, $attr) = @_;
1079     my $value = $attr->value;
1080     my $lws0 = qr/(?>(?>\x0D\x0A)?[\x09\x20])*/;
1081     my $token = qr/[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7E]+/;
1082     my $qs = qr/"(?>[\x00-\x0C\x0E-\x21\x23-\x5B\x5D-\x7E]|\x0D\x0A[\x09\x20]|\x5C[\x00-\x7F])*"/;
1083     if ($value =~ m#\A$lws0($token)$lws0/$lws0($token)$lws0((?>;$lws0$token$lws0=$lws0(?>$token|$qs)$lws0)*)\z#) {
1084     my @type = ($1, $2);
1085     my $param = $3;
1086     while ($param =~ s/^;$lws0($token)$lws0=$lws0(?>($token)|($qs))$lws0//) {
1087     if (defined $2) {
1088     push @type, $1 => $2;
1089     } else {
1090     my $n = $1;
1091     my $v = $2;
1092     $v =~ s/\\(.)/$1/gs;
1093     push @type, $n => $v;
1094     }
1095     }
1096     require Whatpm::IMTChecker;
1097     Whatpm::IMTChecker->check_imt (sub {
1098     my %opt = @_;
1099     $self->{onerror}->(node => $attr, level => $opt{level},
1100     type => 'IMT:'.$opt{type});
1101     }, @type);
1102     } else {
1103     $self->{onerror}->(node => $attr, type => 'IMT:syntax error');
1104     }
1105     },
1106 wakaba 1.2 }),
1107     checker => sub {
1108     my ($self, $todo) = @_;
1109    
1110     unless ($todo->{node}->has_attribute_ns (undef, 'href')) { # MUST
1111     $self->{onerror}->(node => $todo->{node},
1112     type => 'attribute missing:href');
1113     }
1114    
1115 wakaba 1.3 if ($todo->{node}->rel eq $LINK_REL . 'enclosure' and
1116 wakaba 1.2 not $todo->{node}->has_attribute_ns (undef, 'length')) {
1117     $self->{onerror}->(node => $todo->{node}, level => 's',
1118     type => 'attribute missing:length');
1119     }
1120    
1121     my @nodes = (@{$todo->{node}->child_nodes});
1122     my $new_todos = [];
1123 wakaba 1.1
1124     while (@nodes) {
1125     my $node = shift @nodes;
1126     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
1127    
1128     my $nt = $node->node_type;
1129     if ($nt == 1) {
1130 wakaba 1.2 my ($sib, $ch) = $self->_check_get_children ($node, $todo);
1131     unshift @nodes, @$sib;
1132     push @$new_todos, @$ch;
1133     } elsif ($nt == 3 or $nt == 4) {
1134     #
1135     } elsif ($nt == 5) {
1136     unshift @nodes, @{$node->child_nodes};
1137     }
1138     }
1139    
1140     return ($new_todos);
1141     },
1142     };
1143    
1144     $Element->{$ATOM_NS}->{logo} = {
1145     attrs_checker => $GetAtomAttrsChecker->({}),
1146     checker => sub {
1147     my ($self, $todo) = @_;
1148    
1149     my @nodes = (@{$todo->{node}->child_nodes});
1150     my $new_todos = [];
1151    
1152     my $s = '';
1153     while (@nodes) {
1154     my $node = shift @nodes;
1155     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
1156    
1157     my $nt = $node->node_type;
1158     if ($nt == 1) {
1159 wakaba 1.1 ## not explicitly disallowed
1160     $self->{onerror}->(node => $node, type => 'element not allowed');
1161     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
1162     unshift @nodes, @$sib;
1163     push @$new_todos, @$ch;
1164     } elsif ($nt == 3 or $nt == 4) {
1165 wakaba 1.2 $s .= $node->data;
1166 wakaba 1.1 } elsif ($nt == 5) {
1167     unshift @nodes, @{$node->child_nodes};
1168     }
1169     }
1170    
1171 wakaba 1.2 ## NOTE: There MUST NOT be any white space.
1172     Whatpm::URIChecker->check_iri_reference ($s, sub {
1173     my %opt = @_;
1174     $self->{onerror}->(node => $todo->{node}, level => $opt{level},
1175     type => 'URI::'.$opt{type}.
1176     (defined $opt{position} ? ':'.$opt{position} : ''));
1177     });
1178    
1179     ## NOTE: Image SHOULD be 2:1
1180    
1181     return ($new_todos);
1182     },
1183     };
1184    
1185     $Element->{$ATOM_NS}->{published} = $AtomDateConstruct;
1186    
1187     $Element->{$ATOM_NS}->{rights} = $AtomDateConstruct;
1188 wakaba 1.3 ## NOTE: SHOULD NOT be used to convey machine-readable information.
1189 wakaba 1.2
1190     $Element->{$ATOM_NS}->{source} = {
1191     attrs_checker => $GetAtomAttrsChecker->({}),
1192     checker => sub {
1193     my ($self, $todo) = @_;
1194    
1195     my @nodes = (@{$todo->{node}->child_nodes});
1196     my $new_todos = [];
1197     my $has_element = {};
1198     while (@nodes) {
1199     my $node = shift @nodes;
1200     $self->_remove_minuses ($node) and next if ref $node eq 'HASH';
1201    
1202     my $nt = $node->node_type;
1203     if ($nt == 1) {
1204     my $nsuri = $node->namespace_uri;
1205     $nsuri = '' unless defined $nsuri;
1206     my $not_allowed;
1207     if ($nsuri eq $ATOM_NS) {
1208     my $ln = $node->manakai_local_name;
1209     if ($ln eq 'entry') {
1210     $has_element->{entry} = 1;
1211     } elsif ({
1212     generator => 1,
1213     icon => 1,
1214     id => 1,
1215     logo => 1,
1216     rights => 1,
1217     subtitle => 1,
1218     title => 1,
1219     updated => 1,
1220     }->{$ln}) {
1221     unless ($has_element->{$ln}) {
1222     $has_element->{$ln} = 1;
1223     $not_allowed = $has_element->{entry};
1224     } else {
1225     $not_allowed = 1;
1226     }
1227     } elsif ($ln eq 'link') {
1228 wakaba 1.3 if ($node->rel eq $LINK_REL . 'alternate') {
1229     my $type = $node->get_attribute_ns (undef, 'type');
1230     $type = '' unless defined $type;
1231     my $hreflang = $node->get_attribute_ns (undef, 'hreflang');
1232     $hreflang = '' unless defined $hreflang;
1233     my $key = 'link:'.(defined $type ? ':'.$type : '').':'.
1234     (defined $hreflang ? ':'.$hreflang : '');
1235     unless ($has_element->{$key}) {
1236     $has_element->{$key} = 1;
1237     } else {
1238     $not_allowed = 1;
1239     }
1240     }
1241     $not_allowed ||= $has_element->{entry};
1242 wakaba 1.2 } elsif ({
1243     author => 1,
1244     category => 1,
1245     contributor => 1,
1246     }->{$ln}) {
1247     $not_allowed = $has_element->{entry};
1248     } else {
1249     $not_allowed = 1;
1250     }
1251     } else {
1252     ## TODO: extension element
1253     $not_allowed = 1;
1254     }
1255     $self->{onerror}->(node => $node, type => 'element not allowed')
1256     if $not_allowed;
1257     my ($sib, $ch) = $self->_check_get_children ($node, $todo);
1258     unshift @nodes, @$sib;
1259     push @$new_todos, @$ch;
1260     } elsif ($nt == 3 or $nt == 4) {
1261     ## TODO: Are white spaces allowed?
1262     $self->{onerror}->(node => $node, type => 'character not allowed');
1263     } elsif ($nt == 5) {
1264     unshift @nodes, @{$node->child_nodes};
1265     }
1266     }
1267 wakaba 1.1
1268     return ($new_todos);
1269     },
1270     };
1271 wakaba 1.2
1272     $Element->{$ATOM_NS}->{subtitle} = $AtomTextConstruct;
1273    
1274     $Element->{$ATOM_NS}->{summary} = $AtomTextConstruct;
1275    
1276     $Element->{$ATOM_NS}->{title} = $AtomTextConstruct;
1277    
1278     $Element->{$ATOM_NS}->{updated} = $AtomDateConstruct;
1279    
1280     ## TODO: signature element
1281    
1282     ## TODO: simple extension element and structured extension element
1283 wakaba 1.1
1284     $Whatpm::ContentChecker::Namespace->{$ATOM_NS}->{loaded} = 1;
1285    
1286     1;

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24