Mercurial > pub > Impl
view lib/IMPL/DOM/Schema/NodeList.pm @ 416:cc2cf8c0edc2 ref20150831
sync
author | cin |
---|---|
date | Thu, 29 Oct 2015 03:50:25 +0300 |
parents | c6e90e02dd17 |
children |
line wrap: on
line source
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