comparison lib/IMPL/DOM/Schema/NodeSet.pm @ 407:c6e90e02dd17 ref20150831

renamed Lib->lib
author cin
date Fri, 04 Sep 2015 19:40:23 +0300
parents
children
comparison
equal deleted inserted replaced
406:f23fcb19d3c1 407:c6e90e02dd17
1 package IMPL::DOM::Schema::NodeSet;
2 use strict;
3 use warnings;
4
5 use IMPL::Const qw(:prop);
6 use IMPL::declare {
7 require => {
8 Label => 'IMPL::DOM::Schema::Label',
9 ValidationError => 'IMPL::DOM::Schema::ValidationError',
10 AnyNode => '-IMPL::DOM::Schema::AnyNode'
11 },
12 base => [
13 'IMPL::DOM::Node' => sub { nodeName => 'NodeSet' }
14 ],
15 props => [
16 messageUnexpected => { get => 1, set => 1, dom => 1},
17 messageMax => { get => 1, set => 1, dom => 1},
18 messageMin => { get => 1, set => 1, dom => 1}
19 ]
20 };
21
22 sub CTOR {
23 my ($this,%args) = @_;
24
25 $this->messageMax( $args{messageMax} || 'Too many %node.nodeName% nodes');
26 $this->messageMin( $args{messageMin} || '%schemaNode.name% nodes expected');
27 $this->messageUnexpected( $args{messageUnexpected} || 'A %node.nodeName% isn\'t allowed in %node.parentNode.path%');
28 }
29
30 sub Validate {
31 my ($this,$node,$ctx) = @_;
32
33 my @errors;
34
35 my %nodes;
36 my $anyNode;
37
38 foreach (@{$this->childNodes}) {
39 if ($_->isa(AnyNode)) {
40 $anyNode = {schemaNode => $_, min => $_->minOccur, max => $_->maxOccur eq 'unbounded' ? undef : $_->maxOccur , seen => 0 };
41 } else {
42 $nodes{$_->name} = {schemaNode => $_, min => $_->minOccur, max => $_->maxOccur eq 'unbounded' ? undef : $_->maxOccur , seen => 0 };
43 }
44 }
45
46 foreach my $child ( @{$node->childNodes} ) {
47 if (my $info = $nodes{$child->nodeName} || $anyNode) {
48 $info->{seen}++;
49 push @errors,ValidationError->new(
50 schemaNode => $info->{schemaNode},
51 node => $child,
52 parent => $node,
53 message => $this->_MakeLabel($this->messageMax)
54 ) if ($info->{max} and $info->{seen} > $info->{max});
55
56 if (my @localErrors = $info->{schemaNode}->Validate($child)) {
57 push @errors,@localErrors;
58 }
59 } else {
60 push @errors, ValidationError->new(
61 node => $child,
62 parent => $node,
63 message => $this->_MakeLabel($this->messageUnexpected)
64 )
65 }
66 }
67
68 foreach my $info (values %nodes) {
69 push @errors, ValidationError->new(
70 schemaNode => $info->{schemaNode},
71 parent => $node,
72 message => $this->_MakeLabel($this->messageMin)
73 ) if $info->{min} > $info->{seen};
74 }
75
76 return @errors;
77 }
78
79 sub _MakeLabel {
80 my ($this,$label) = @_;
81
82 if ($label =~ /^ID:(\w+)$/) {
83 return Label->new($this->document->stringMap, $1);
84 } else {
85 return $label;
86 }
87 }
88
89 1;
90
91 __END__
92
93 =pod
94
95 =head1 DESCRIPTION
96
97 Содержимое для сложного узла. Порядок не важен. Дочерними элементами могут быть
98 только C<IMPL::DOM::Schema::ComplexNode> и C<IMPL::DOM::Schema::SimpleNode>.
99
100 При проверке данного правила, проверяются имеющиеся элементы на соответсие схемы
101 и количества встречаемости, после чего проверяются количественные ограничения
102 для несуществующих элементов.
103
104 =cut