49
|
1 package IMPL::DOM::Schema::NodeSet;
|
|
2 use strict;
|
|
3 use warnings;
|
|
4
|
|
5 use base qw(IMPL::DOM::Node);
|
|
6 use IMPL::Class::Property;
|
|
7
|
|
8 our %CTOR = (
|
|
9 'IMPL::DOM::Node' => sub { nodeName => 'NodeSet' }
|
|
10 );
|
|
11
|
|
12 BEGIN {
|
|
13 public property messageUnexpected => prop_all;
|
|
14 public property messageMax => prop_all;
|
|
15 public property messageMin => prop_all;
|
|
16 }
|
|
17
|
|
18 sub CTOR {
|
|
19 my ($this,%args) = @_;
|
|
20
|
|
21 $this->messageMax( $args{messageMax} || 'Too many %Node.nodeName% nodes');
|
|
22 $this->messageMin( $args{messageMin} || '%Schema.name% nodes expected');
|
|
23 $this->messageUnexpected( $args{messageUnexpected} || 'A %Node.nodeName% isn\'t allowed in %Node.parentNode.path%');
|
|
24 }
|
|
25
|
|
26 sub Validate {
|
|
27 my ($this,$node) = @_;
|
|
28
|
|
29 my @errors;
|
|
30
|
|
31 my %nodes;
|
|
32 my $anyNode;
|
|
33 foreach (@{$this->childNodes}) {
|
|
34 if ($_->isa('IMPL::DOM::Schema::AnyNode')) {
|
|
35 $anyNode = {Schema => $_, Min => $_->minOccur, Max => $_->maxOccur eq 'unbounded' ? undef : $_->maxOccur , Seen => 0 };
|
|
36 } else {
|
|
37 $nodes{$_->name} = {Schema => $_, Min => $_->minOccur, Max => $_->maxOccur eq 'unbounded' ? undef : $_->maxOccur , Seen => 0 };
|
|
38 }
|
|
39 }
|
|
40
|
|
41 foreach my $child ( @{$node->childNodes} ) {
|
|
42 if (my $info = $nodes{$child->nodeName} || $anyNode) {
|
|
43 $info->{Seen}++;
|
|
44 push @errors,new IMPL::DOM::Schema::ValidationError (
|
|
45 Source => $this,
|
|
46 Node => $child,
|
102
|
47 Parent => $node,
|
49
|
48 Schema => $info->{Schema},
|
|
49 Message => $this->messageMax
|
|
50 ) if ($info->{Max} and $info->{Seen} > $info->{Max});
|
|
51
|
|
52 if (my @localErrors = $info->{Schema}->Validate($child)) {
|
|
53 push @errors,@localErrors;
|
|
54 }
|
|
55 } else {
|
|
56 push @errors, new IMPL::DOM::Schema::ValidationError (
|
|
57 Source => $this,
|
|
58 Node => $child,
|
102
|
59 Parent => $node,
|
49
|
60 Message => $this->messageUnexpected
|
|
61 )
|
|
62 }
|
|
63 }
|
|
64
|
|
65 foreach my $info (values %nodes) {
|
|
66 push @errors, new IMPL::DOM::Schema::ValidationError (
|
|
67 Source => $this,
|
|
68 Schema => $info->{Schema},
|
102
|
69 Parent => $node,
|
49
|
70 Message => $this->messageMin
|
|
71 ) if $info->{Min} > $info->{Seen};
|
|
72 }
|
|
73
|
|
74 return @errors;
|
|
75 }
|
|
76
|
|
77 1;
|
|
78
|
|
79 __END__
|
|
80
|
|
81 =pod
|
|
82
|
|
83 =head1 DESCRIPTION
|
|
84
|
|
85 Содержимое для сложного узла. Порядок не важен. Дочерними элементами могут быть
|
|
86 только C<IMPL::DOM::Schema::ComplexNode> и C<IMPL::DOM::Schema::SimpleNode>.
|
|
87
|
|
88 При проверке данного правила, проверяются имеющиеся элементы на соответсие схемы
|
|
89 и количества встречаемости, после чего проверяются количественные ограничения
|
|
90 для несуществующих элементов.
|
|
91
|
|
92 =cut
|