Mercurial > pub > Impl
diff lib/IMPL/DOM/Schema/NodeList.pm @ 407:c6e90e02dd17 ref20150831
renamed Lib->lib
author | cin |
---|---|
date | Fri, 04 Sep 2015 19:40:23 +0300 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/IMPL/DOM/Schema/NodeList.pm Fri Sep 04 19:40:23 2015 +0300 @@ -0,0 +1,114 @@ +package IMPL::DOM::Schema::NodeList; +use strict; +use warnings; + + +use IMPL::declare { + require => { + ValidationError => 'IMPL::DOM::Schema::ValidationError', + AnyNode => '-IMPL::DOM::Schema::AnyNode', + Label => 'IMPL::DOM::Schema::Label' + }, + base => [ + 'IMPL::DOM::Node' => sub { nodeName => 'NodeList' } + ], + props => [ + messageUnexpected => { get => 1, set => 1, dom => 1 }, + messageNodesRequired => { get => 1, set => 1, dom => 1} + ] +}; + +sub CTOR { + my ($this,%args) = @_; + + $this->messageUnexpected($args{messageUnexpected} || 'A %node.nodeName% isn\'t allowed in %node.parentNode.path%'); + $this->messageNodesRequired($args{messageNodesRequired} || 'A %schemaNode.name% is required in the node %parent.path%'); +} + +sub Validate { + my ($this,$node,$ctx) = @_; + + my @nodes = map { + {nodeName => $_->name, anyNode => $_->isa(AnyNode) , schemaNode => $_, max => $_->maxOccur eq 'unbounded' ? undef : $_->maxOccur, min => $_->minOccur, seen => 0 } + } @{$this->childNodes}; + + my $info = shift @nodes; + + foreach my $child ( @{$node->childNodes} ) { + #skip schema elements + while ($info and not $info->{anyNode} and $info->{nodeName} ne $child->nodeName) { + # if possible of course :) + return ValidationError->new ( + message => $this->_MakeLabel( $this->messageUnexpected ), + node => $child, + parent => $node, + schemaNode => $info->{schemaNode} + ) if $info->{min} > $info->{seen}; # we trying to skip a schema node which has a quantifier + + $info = shift @nodes; + } + + # return error if no more children allowed + return ValidationError->new ( + message => $this->_MakeLabel( $this->messageUnexpected ), + node => $child, + parent => $node + ) unless $info; + + # it's ok, we found schema element for child + + # validate + while (my @errors = $info->{schemaNode}->Validate( $child ) ) { + if( $info->{anyNode} and $info->{seen} >= $info->{min} ) { + # in case of any or switch node, skip it if possible + next if $info = shift @nodes; + } + return @errors; + } + + $info->{seen}++; + + # check count limits + return ValidationError->new( + message => $this->_MakeLabel( $this->messageUnexpected ), + node => $child, + parent => $node, + schemaNode => $info->{schemaNode}, + ) if $info->{max} and $info->{seen} > $info->{max}; + } + + # no more children left (but may be should :) + while ($info) { + return ValidationError->new( + message => $this->_MakeLabel( $this->messageNodesRequired ), + parent => $node, + schemaNode => $info->{schemaNode} + ) if $info->{seen} < $info->{min}; + + $info = shift @nodes; + } + return; +} + +sub _MakeLabel { + my ($this,$label) = @_; + + if ($label =~ /^ID:(\w+)$/) { + return Label->new($this->document->stringMap, $1); + } else { + return $label; + } +} + +1; + +__END__ + +=pod + +=head1 DESCRIPTION + +Содержимое для сложного узла. Порядок важен. Дочерними элементами могут быть +только C<IMPL::DOM::Schema::ComplexNode> и C<IMPL::DOM::Schema::SimpleNode>. + +=cut