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 {
|
125
|
27 my ($this,$node,$ctx) = @_;
|
49
|
28
|
|
29 my @errors;
|
|
30
|
|
31 my %nodes;
|
|
32 my $anyNode;
|
125
|
33 my $sourceSchema = $ctx->{Source} || $this->parentNode;
|
|
34
|
49
|
35 foreach (@{$this->childNodes}) {
|
|
36 if ($_->isa('IMPL::DOM::Schema::AnyNode')) {
|
|
37 $anyNode = {Schema => $_, Min => $_->minOccur, Max => $_->maxOccur eq 'unbounded' ? undef : $_->maxOccur , Seen => 0 };
|
|
38 } else {
|
|
39 $nodes{$_->name} = {Schema => $_, Min => $_->minOccur, Max => $_->maxOccur eq 'unbounded' ? undef : $_->maxOccur , Seen => 0 };
|
|
40 }
|
|
41 }
|
|
42
|
|
43 foreach my $child ( @{$node->childNodes} ) {
|
|
44 if (my $info = $nodes{$child->nodeName} || $anyNode) {
|
|
45 $info->{Seen}++;
|
|
46 push @errors,new IMPL::DOM::Schema::ValidationError (
|
125
|
47 Source => $sourceSchema,
|
49
|
48 Node => $child,
|
102
|
49 Parent => $node,
|
49
|
50 Schema => $info->{Schema},
|
|
51 Message => $this->messageMax
|
|
52 ) if ($info->{Max} and $info->{Seen} > $info->{Max});
|
|
53
|
|
54 if (my @localErrors = $info->{Schema}->Validate($child)) {
|
|
55 push @errors,@localErrors;
|
|
56 }
|
|
57 } else {
|
|
58 push @errors, new IMPL::DOM::Schema::ValidationError (
|
125
|
59 Source => $sourceSchema,
|
49
|
60 Node => $child,
|
102
|
61 Parent => $node,
|
49
|
62 Message => $this->messageUnexpected
|
|
63 )
|
|
64 }
|
|
65 }
|
|
66
|
|
67 foreach my $info (values %nodes) {
|
|
68 push @errors, new IMPL::DOM::Schema::ValidationError (
|
125
|
69 Source => $sourceSchema,
|
49
|
70 Schema => $info->{Schema},
|
102
|
71 Parent => $node,
|
49
|
72 Message => $this->messageMin
|
|
73 ) if $info->{Min} > $info->{Seen};
|
|
74 }
|
|
75
|
|
76 return @errors;
|
|
77 }
|
|
78
|
|
79 1;
|
|
80
|
|
81 __END__
|
|
82
|
|
83 =pod
|
|
84
|
|
85 =head1 DESCRIPTION
|
|
86
|
|
87 Содержимое для сложного узла. Порядок не важен. Дочерними элементами могут быть
|
|
88 только C<IMPL::DOM::Schema::ComplexNode> и C<IMPL::DOM::Schema::SimpleNode>.
|
|
89
|
|
90 При проверке данного правила, проверяются имеющиеся элементы на соответсие схемы
|
|
91 и количества встречаемости, после чего проверяются количественные ограничения
|
|
92 для несуществующих элементов.
|
|
93
|
|
94 =cut
|