| 
49
 | 
     1 package IMPL::DOM::Schema::NodeList;
 | 
| 
 | 
     2 use strict;
 | 
| 
 | 
     3 use warnings;
 | 
| 
 | 
     4 use base qw(IMPL::DOM::Node);
 | 
| 
 | 
     5 
 | 
| 
 | 
     6 use IMPL::Class::Property;
 | 
| 
 | 
     7 require IMPL::DOM::Schema::ValidationError;
 | 
| 
 | 
     8 
 | 
| 
 | 
     9 our %CTOR = (
 | 
| 
 | 
    10     'IMPL::DOM::Node' => sub { nodeName => 'NodeList' }
 | 
| 
 | 
    11 );
 | 
| 
 | 
    12 
 | 
| 
 | 
    13 BEGIN {
 | 
| 
 | 
    14     public property messageUnexpected => prop_all;
 | 
| 
 | 
    15     public property messageNodesRequired => prop_all;
 | 
| 
 | 
    16 }
 | 
| 
 | 
    17 
 | 
| 
 | 
    18 sub CTOR {
 | 
| 
 | 
    19     my ($this,%args) = @_;
 | 
| 
 | 
    20     
 | 
| 
 | 
    21     $this->messageUnexpected($args{messageUnexpected} || 'A %Node.nodeName% isn\'t allowed in %Node.parentNode.path%');
 | 
| 
102
 | 
    22     $this->messageNodesRequired($args{messageNodesRequired} || 'A %Schema.name% is required in the node %Parent.path%');
 | 
| 
49
 | 
    23 }
 | 
| 
 | 
    24 
 | 
| 
 | 
    25 sub Validate {
 | 
| 
125
 | 
    26     my ($this,$node,$ctx) = @_;
 | 
| 
49
 | 
    27     
 | 
| 
 | 
    28     my @nodes = map {
 | 
| 
 | 
    29         {nodeName => $_->name, anyNode => $_->isa('IMPL::DOM::Schema::AnyNode') , Schema => $_, Max => $_->maxOccur eq 'unbounded' ? undef : $_->maxOccur, Min => $_->minOccur, Seen => 0 }
 | 
| 
 | 
    30     } @{$this->childNodes};
 | 
| 
 | 
    31     
 | 
| 
 | 
    32     my $info = shift @nodes;
 | 
| 
125
 | 
    33     my $sourceSchema = $ctx->{Source} || $this->parentNode;
 | 
| 
49
 | 
    34     
 | 
| 
 | 
    35     foreach my $child ( @{$node->childNodes} ) {
 | 
| 
 | 
    36         #skip schema elements
 | 
| 
 | 
    37         while ($info and not $info->{anyNode} and $info->{nodeName} ne $child->nodeName) {
 | 
| 
 | 
    38             # if possible of course :)
 | 
| 
 | 
    39             return new IMPL::DOM::Schema::ValidationError (
 | 
| 
 | 
    40                 Message => $this->messageUnexpected,
 | 
| 
 | 
    41                 Node => $child,
 | 
| 
102
 | 
    42                 Parent => $node,
 | 
| 
49
 | 
    43                 Schema => $info->{Schema},
 | 
| 
125
 | 
    44                 Source => $sourceSchema
 | 
| 
49
 | 
    45             ) if $info->{Min} > $info->{Seen};
 | 
| 
 | 
    46             
 | 
| 
 | 
    47             $info = shift @nodes;
 | 
| 
 | 
    48         }
 | 
| 
 | 
    49         
 | 
| 
 | 
    50         # return error if no more children allowed
 | 
| 
 | 
    51         return new IMPL::DOM::Schema::ValidationError (
 | 
| 
 | 
    52             Message => $this->messageUnexpected,
 | 
| 
 | 
    53             Node => $child,
 | 
| 
102
 | 
    54             Parent => $node,
 | 
| 
125
 | 
    55             Source => $sourceSchema
 | 
| 
49
 | 
    56         ) unless $info;
 | 
| 
 | 
    57         
 | 
| 
 | 
    58         # it's ok, we found schema element for child
 | 
| 
 | 
    59         # but it may be any node or switching node wich would not satisfy current child
 | 
| 
 | 
    60 
 | 
| 
 | 
    61         # validate
 | 
| 
 | 
    62         while (my @errors = $info->{Schema}->Validate($child)) {
 | 
| 
 | 
    63             if( $info->{anyNode} and $info->{Seen} >= $info->{Min} ) {
 | 
| 
 | 
    64                 # in case of any or switch node, skip it if possible
 | 
| 
 | 
    65                 next if $info = shift @nodes;
 | 
| 
 | 
    66             }
 | 
| 
 | 
    67             return @errors;
 | 
| 
 | 
    68         }
 | 
| 
 | 
    69         
 | 
| 
 | 
    70         $info->{Seen}++;
 | 
| 
 | 
    71         
 | 
| 
 | 
    72         # check count limits
 | 
| 
 | 
    73         return new IMPL::DOM::Schema::ValidationError (
 | 
| 
 | 
    74             Error => 1,
 | 
| 
 | 
    75             Message => $this->messageUnexpected,
 | 
| 
 | 
    76             Node => $child,
 | 
| 
102
 | 
    77             Parent => $node,
 | 
| 
125
 | 
    78             Source => $sourceSchema,
 | 
| 
49
 | 
    79         ) if $info->{Max} and $info->{Seen} > $info->{Max};
 | 
| 
 | 
    80     }
 | 
| 
 | 
    81     
 | 
| 
 | 
    82     # no more children left (but may be should :)
 | 
| 
 | 
    83     while ($info) {
 | 
| 
 | 
    84         return new IMPL::DOM::Schema::ValidationError (
 | 
| 
 | 
    85             Error => 1,
 | 
| 
 | 
    86             Message => $this->messageNodesRequired,
 | 
| 
125
 | 
    87             Source => $sourceSchema,
 | 
| 
102
 | 
    88             Parent => $node,
 | 
| 
49
 | 
    89             Schema => $info->{Schema}
 | 
| 
 | 
    90         ) if $info->{Seen} < $info->{Min};
 | 
| 
 | 
    91         
 | 
| 
 | 
    92         $info = shift @nodes;
 | 
| 
 | 
    93     }
 | 
| 
 | 
    94     return;
 | 
| 
 | 
    95 }
 | 
| 
 | 
    96 
 | 
| 
 | 
    97 1;
 | 
| 
 | 
    98 
 | 
| 
 | 
    99 __END__
 | 
| 
 | 
   100 
 | 
| 
 | 
   101 =pod
 | 
| 
 | 
   102 
 | 
| 
 | 
   103 =head1 DESCRIPTION
 | 
| 
 | 
   104 
 | 
| 
 | 
   105 Содержимое для сложного узла. Порядок важен. Дочерними элементами могут быть
 | 
| 
 | 
   106 только C<IMPL::DOM::Schema::ComplexNode> и C<IMPL::DOM::Schema::SimpleNode>.
 | 
| 
 | 
   107 
 | 
| 
 | 
   108 =cut
 |