Mercurial > pub > Impl
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 |