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 |
